你真的会用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锁住的资源是否是同一个对象。

 

posted @ 2021-06-17 17:49  Mr_差不多  阅读(72)  评论(0)    收藏  举报