synchronized关键字在java多线程编程过程中非常的有用,不过在编程过程中由于对synchronized的理解不足,也会有很多坑。
synchronized(object)是最常用的方法,它可以锁住需要访问的代码块,使只有一个线程访问而达到同步的目的。例如如下代码:
public class MulThreadTest {
public static int a = 0;
public void addInt1(){
synchronized(this){
a++;
System.out.println(a);
}
}
public static void main(String[] args){
final MulThreadTest test = new MulThreadTest();
for(int i=0;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int j=0;j<100;j++)
test.addInt1();
}
}).start();
}
}
}
运行上述代码没有问题,synchronized使用this做锁对象,即使用的是引用的对象test做锁对象。因为synchronized包含的代码块包含了方法区里的所有代码,所以方法addInt1()等同如下形式:
public synchronized void addInt2(){
a++;
System.out.println(a);
}
如果main函数的方法将final对象test放入多线程中,如下:
public static void main(String[] args) throws InterruptedException {
for(int i=0;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
MulThreadTest test = new MulThreadTest();
for(int j=0;j<100;j++)
test.addInt1();
}
}).start();
}
}
此时,运行代码会发现结果不是我们想要的。因为此时运行的每一个线程都有一个锁对象test,他们之间没有做到互斥访问,此时我们就需要更改addInt1()方法如下:
public void addInt3(){
synchronized (MulThreadTest.class) {
a++;
System.out.println(a);
}
}
将锁加在类上或者声明一个静态对象做为锁对象 :
static Object object = new Object();
总结:
synchronized的多线程使用关键是看哪个作为锁对象,如果锁的不是同一个对象,那么就无法达到同步的目的。