你真的会用synchronized么?
相信屏幕前的你一定已经对synchronized有了一定的了解,所以我们直接show code
public class Sync { public synchronized void f1() { //doSomeThing(); } public synchronized static void f2() { //doSomeThing(); } }
你能讲出synchronized 在两个方法中锁作用的对象么?如果能,那么恭喜你已经基本上掌握了synchronized的使用。如果不能,没关系接着往下看,阅读本文你就会掌握synchronized的正确使用姿势。
1 public class Sync { 2 3 public void f1() { 4 synchronized(this){ 5 //doSomeThing(); 6 } 7 8 } 9 10 public synchronized static void f2() { 11 synchronized (Sync.class){ 12 //doSomeThing(); 13 } 14 } 15 16 }
怎么样?找到答案了么?
别急,搬好小板凳我们来聊聊。
首先我们能从代码中很轻易的发现方法f1()是非静态成员函数,方法f2()静态成员函数。我们知道静态成员函数属于类的类对象,而非静态成员函数属于类属于实例对象。所以说方法f1()被synchronized锁住的是实例对象。方法f2()中被synchronized锁住的是类的类对象。在这里我们要清楚的知道,这是不同的2把锁。
public class AccountSync implements Runnable { static AccountSync sync = new AccountSync(); static int i = 0; public synchronized void increase() { i++; } @Override public void run() { for (int j = 0; j < 10000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(sync); Thread thread1 = new Thread(sync); thread.start(); thread1.start(); thread.join(); thread1.join(); System.out.println(i); } }
输出结果为:20000
public class AccountSyncBad implements Runnable { static int i = 0; public synchronized void increase() { i++; } @Override public void run() { for (int j = 0; j < 10000; j++) { increase(); } } public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(new AccountSyncBad()); Thread thread1 = new Thread(new AccountSyncBad()); thread.start(); thread1.start(); thread.join(); thread1.join(); System.out.println(i); } }
输出结果一般都比20000要小。很明显上述代码中有Bug,虽然在方法increase()中也设置了synchroinzed。但是两个线程分别创建了两个实例,而synchroinzed锁住的是两个不同的实例,所以锁是没有效果的。基于上面的代码很容易修改,用static修饰increase()方法即可。
正确使用synchroinzed的前提是我们需要分析清楚synchroinzed锁住的资源是否是同一个对象。

浙公网安备 33010602011771号