概述
多个线程中,如果每个线程操作的对象是不同的,那么就会为每个线程产生一把锁,这个时候,在不同的线程中,锁是不起作用的。
代码
MultiThread.java
public class MultiThread {
private int num = 0;
public synchronized void printNum(String tag) throws InterruptedException {
if (tag.equals("a")) {
num = 100;
System.out.println("tag a, set num over!");
Thread.sleep(1000);
} else {
num = 200;
System.out.println("tag b, set num over!");
}
System.out.println("tag " + tag + ", num = " + num);
}
public static void main(String[] args) {
MultiThread m1 = new MultiThread();
MultiThread m2 = new MultiThread();
Thread t1 = new Thread(() -> {
try{
m1.printNum("a");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try{
m2.printNum("b");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
}
}
说明:定义了一个printNum方法,并给这个方法加了锁,这个方法内部是一个简单的if else判断而已,很简单。底下的main方法中,创建了两个MultiThread对象,分别为m1和m2,接下来又创建l了两个线程,分别是t1和t2,这两个线程的实现方式是直接使用匿名类创建对象的方式,可以直接使用接口,这里又使用了lamda表达式,所以看起来比较简略,实际上是创建的Runnable接口的对象,其中括号中的内容是覆写run方法的内容,可以看到两个不同的线程分别调用了不同对象的printNum方法,那么结果会是怎样的呢?
tag a, set num over!
tag b, set num over!
tag b, num = 200
tag a, num = 100
结果和我们预想的不对吗?当然不对,预想的应该是
tag a, set num over!
tag a, num = 100
tag b, set num over!
tag b, num = 200
这样才对,因为我们加了synchronized 关键字啊。
原因是这样的,因为我们这两个线程分别调用的是两个对象的printNum方法,虽然进行了加锁,但是他们并不是一个对象,也就是说,这个同步锁是加在对象上的,并没有加在类级别上,不同的对象调用这个方法,同步锁是没有用的。
那么如何让对象方法加锁执行呢,也就是让同步锁起作用呢,那就需要使用static关键字,代码修改为:
private static int num = 0;
public static synchronized void printNum(String tag) throws InterruptedException {
if (tag.equals("a")) {
num = 100;
System.out.println("tag a, set num over!");
Thread.sleep(1000);
} else {
num = 200;
System.out.println("tag b, set num over!");
}
System.out.println("tag " + tag + ", num = " + num);
}
这样子再次执行查看效果:
tag a, set num over!
tag a, num = 100
tag b, set num over!
tag b, num = 200
结果就和我们预期的一样了,那么为什么加上static之后就可以了呢,因为我们加了static关键字之后,这个方法就变成了类方法,也就是说,这个方法是和类相关的,和某个对象是无关的了,所以就可以达到加锁的效果了。所以我们查看结果,就是a先执行,然后b才执行。
总结:
synchronized取得的锁都是对象锁,而不是把一段代码当做锁,所以示例代码中那个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),两个对象,线程获取的就是两个不同的锁,他们互不影响。
有一种情况则是相同的锁,即在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)