即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

synchronized同步办法2

编程语言 limin0983 10℃ 0评论

    接上一篇synchronized同步方法

关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法当作锁。对于多个线程同时执行一个对象的一个同步方法,哪个线程先执行带synchronized关键字的方法,哪个线程就持有了该方法所属对象的锁Lock,那么其他线程只能呈等待状态。



2. 如何通过synchronized关键字解决脏读

代码:

package testSynchronized;

public class PublicVar {
    public String username ="A";
    public String password = "AA";
    synchronized public void setValue(String username,String password){
        try{
            this.username = username;
            Thread.sleep(5000);
            this.password = password;
            System.out.println("setValue method thread name = "+Thread.currentThread().getName()+" username = "+username
                    +", password = "+password);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
    }
    
    
      public void getValue(){
        System.out.println("getValue method thread name ="+Thread.currentThread().getName()+
                " username = "+username +", password = "+password);
      }






}






package testSynchronized;

public class ThreadA extends Thread {
 private PublicVar publicVar;
 public ThreadA(PublicVar publicVar){
  this.publicVar = publicVar;
 }
 @Override
 public void run() {
  publicVar.setValue("B", "BB");
 }
 
}


package testSynchronized;

public class Test {
 public static void main(String[] args) {
 PublicVar publicVar = new PublicVar();
 ThreadA threadA = new ThreadA(publicVar);
 threadA.start();
 try {
  Thread.sleep(1000);
 } catch (InterruptedException e) {
  
  e.printStackTrace();
 }
 publicVar.getValue();
 }
}



运行结果:

getValue method thread name =main username = B, password = AA//出现脏读
setValue method thread name = Thread-0 username = B, password = BB



若将getValue() 前加上synchronized关键字,就不会出现这种情况了。

 sunchronized public void getValue(){
        System.out.println("getValue method thread name ="+Thread.currentThread().getName()+
                " username = "+username +", password = "+password);
      }





运行结果:

setValue method thread name = Thread-0 username = B, password = BB
getValue method thread name =main username = B, password = BB


当A线程调用anyObject对象的同步方法(加入synchronized关键字)X时,A线程就获得了X方法锁,更准确的将是:获得了X方法所属对象的锁,所以其他线程必须等到A线程执行完毕才可以调用X方法,但是B线程可以随意调用其他的非synchronized同步方法。

当A线程调用了anyObject对象的同步方法时X时,A线程就获得了X方法所属对象的锁,所以其他线程必须等到A线程执行完毕才可以调用X方法,二如果B线程调用了其他的同步方法(不是X方法),也必须等到A线程将X方法执行完,也就是A线程释放了对象锁后才可以调用。

3.synchronized 锁重入

   关键字synchronized拥有锁重入的功能,也就是在使用synchronized时,当一个线程得到了一个对象锁后,再次请求此对象锁时是可以再次得到的该锁的。这也证明在一个synchronized方法/块的内部调用本类的其他synchronized方法/块时,是永远可以得到锁的。

代码:

package testSynchronized;

public class Service {
 synchronized public void service1(){
  System.out.println("service1");
  service2();
 }

 synchronized public void service2() {
  System.out.println("service2");
  service3();
  
 }

 synchronized public void service3() {
  System.out.println("service3");
 }
}


package testSynchronized;

public class Main {
 public static void main(String[] args) {
  Thread thread1 = new Thread(){
   @Override
   public void run() {
    super.run();
    Service service = new Service();
    service.service1();
   }
   
  };
  thread1.start();
 }
 
}



运行结果:

service1
service2
service3



    “可重入锁”的概念是:自己可以再次获取自己的内部锁。 例如:由1个线程获得了某个对象的锁,此时这个对象锁还没有被释放,当该线程再次想要获取这个对象锁时是可以获取的,如果不可获取锁重入的话,就会造成死锁。

可重入锁也支持在父子类继承的环境中。

package testSynchronized;


public class Parent {
 public int i = 10;
 synchronized public void operateParentMethod(){
  try {
   i--;
   System.out.println("Parent print i = "+i);
   Thread.sleep(1000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  
 }
}


package testSynchronized;

public class Son extends Parent {
 synchronized public void operateSonMethod(){
  try {
   while(i >0){
    i--;
    System.out.println("Son print i = "+i);
    Thread.sleep(1000);
    this.operateParentMethod();//子类在自己的同步方法中调用父类的同步方法
   } 
   
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}


package testSynchronized;

public class MyThread extends Thread {

 @Override
 public void run() {
  super.run();
  Son son = new Son();
  son.operateSonMethod();
 }
 
}


package testSynchronized;

public class Run {
 public static void main(String[] args) {
  Thread thread = new MyThread();
  thread.start();
 }
}

运行结果:

Son print i = 9
Parent print i = 8
Son print i = 7
Parent print i = 6
Son print i = 5
Parent print i = 4
Son print i = 3
Parent print i = 2
Son print i = 1
Parent print i = 0



运行结果说明:当存在父子类继承关系时,子类完全可以通过“可重入锁”调用父类的同步方法。



转载请注明:CodingBlog » synchronized同步办法2

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情