• 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的两大不足

  • 相关阅读:
    MySQL数据库8(四)数据表基本操作
    MYSQL 配置文件
    MySQL数据库8(三)数据库基本操作
    flink-connector-kafka consumer的topic分区分配源码
    kafka consumer assign 和 subscribe模式差异分析
    kafka 配置kerberos校验以及开启acl实践
    二路归并排序的java实现
    storm RollingTopWords 实时top-N计算任务窗口设计
    PriorityBlockingQueue优先队列的二叉堆实现
    堆排序算法的java实现
  • 原文地址:https://www.cnblogs.com/kaituorensheng/p/10079916.html
Copyright © 2020-2023  润新知