synchronized锁住的是代码还是对象

不同的对象

public class Sync {
    public synchronized void test() {
        System.out.println("test start");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test end");
    }
}

#

public class MyThread extends Thread{
    public void run() {
        Sync sync = new Sync();
        sync.test();
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; ++i) {
            Thread thread = new MyThread();
            thread.start();
        }
    }
}

执行结果

test start
test start
test start
test end
test end
test end  

现象

在MyThread中,每次都new一个新的Sync对象,可以看到代码块test虽然被加了synchonized但是还是并行执行的,初步结论:锁住的不是代码块

同一个对象

public class MyThread2 extends Thread{
    public Sync sync;
    MyThread2(Sync sync) {
        this.sync = sync;
    }

    public void run() {
        System.out.println("hi....");
        sync.test();
    }

    public static void main(String[] args) {
        Sync sync = new Sync();
        for (int i = 0; i < 3; ++i) {
            Thread thread = new MyThread2(sync);
            thread.start();
        }
    }

执行结果

hi....
test start
hi....
hi....
test end
test start
test end
test start
test end  

现象

可以看到当他们共用一个对象的时候,synchonized起了作用,这块代码是串行执行的

结论

锁住的是对象

如何在多对象的时候任然锁住代码?

解决也很简单,只要锁住同一个对象就行了。例如:synchronized后的括号中锁同一个固定对象,这样就行了。

这样是没问题,但是,比较多的做法是让synchronized锁这个类对应的Class对象。

public class Sync2 {
    public void test() {
        synchronized (Sync2.class) {
            System.out.println("test start");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("test end");
        }
    }
}

#

public class MyThread3 extends Thread{
    public void run() {
        Sync2 sync = new Sync2();
        sync.test();
    }

    public static void main(String[] args) {
        for (int i = 0; i < 3; ++i) {
            Thread thread = new MyThread3();
            thread.start();
        }
    }
}

执行结果

test start
test end
test start
test end
test start
test end

synchronized的两大不足

  • 由于我们没办法设置synchronized关键字在获取锁的时候等待时间,所以synchronized可能会导致线程为了加锁而无限期地处于阻塞状态
  • 使用synchronized关键字等同于使用了互斥锁,即其他线程都无法获得锁对象的访问权。这种策略对于读多写少的应用而言是很不利的,因为即使多个读者看似可以并发运行,但他们实际上还是串行的,并将最终导致并发性能的下降。 

虽然synchronized已经作为一个关键字被固化在Java语言中了,但它只提供了一种相当保守的线程安全策略,且该策略开放给程序员的控制能力极弱

参考

synchonized控制对象还是代码段

synchronized的两大不足

 

posted @ 2018-12-06 22:04  jihite  阅读(7660)  评论(0编辑  收藏  举报