一、前述
本文讲述的是多个对象访问同步方法的 demo
二、多个对象多个锁
在前面的文章中,讲述的都是一个对象访问方法局部变量、访问实例变量,本文是多个对象访问实例变量,读者不妨思考下,会有什么样的姐结果存在?
demo 代码如下:
public class SynTestA {
private int num = 0;
public synchronized void addA(String name){
try {
if(name.equals("a")){
num = 100;
System.out.println("a set over");
Thread.sleep(2000);
}else{
num = 200;
System.out.println("b set over");
}
System.out.println(name + " num = " + num);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public class ThreadA extends Thread{
private SynTestA synTestA;
public ThreadA(SynTestA synTestA){
super();
this.synTestA = synTestA;
}
@Override
public void run(){
super.run();
synTestA.addA("a");
}
}
public class ThreadB extends Thread{
private SynTestA synTestA;
public ThreadB(SynTestA synTestA){
super();
this.synTestA = synTestA;
}
@Override
public void run(){
super.run();
synTestA.addA("b");
}
}
public class Run {
public static void main(String[] args) {
SynTestA synTestA = new SynTestA();
SynTestA synTestB = new SynTestA();
ThreadA threadA = new ThreadA(synTestA);
threadA.start();
ThreadB threadB = new ThreadB(synTestB);
threadB.start();
}
}
运行结果:
a set over
b set over
b num = 200
a num = 100
1、可以看到,即使我们在方法前面加了关键字 synchronized ,但是从结果来看,是异步打印的,而不是同步,看到这里读者就会问,为什么之前加了同步的关键字可以同步打印,这里是异步打印的。
2、其实这里是两个线程分别访问同一个类的两个实例里的同步方法,由于这里创建了两个业务对象,就会存在两个对象锁,所以两个线程不会竞争锁,自然就是异步执行了,在本 demo 的运行结果中,就会交叉打印。
3、java中的每个对象都有一个锁,当访问某个对象的 synchronized 方法时,表示将该对象锁住,此时其他任何线程都无法在去访问该 syncronized 方法了,直到之前的那个线程执行方法完毕后,其他线程才有可能去访问该synchronized 方法。
4、关键字 syncronized 获取的都是对象头里面的锁,而不是说一段代码或者一个方法作为锁,所以在上面的 demo 里,哪个线程先访问到同步的方法,哪个线程就会拥有该方法所属对象的锁,其他后续的线程就只能等待状态,当然前提是访问的是同一个对象。如果是多个线程访问的多个对象,那么在访问的时候,jvm 就会创建多个锁,例如上面的 demo 里就是创建了两个对象,所以就会创建两个锁,第二个线程就不会等待