• Java并发控制(synchronized、ReentrantLock、CountDownLatch)


    参考资料:

    https://blog.csdn.net/zcl_love_wx/article/details/93977947

    https://zhuanlan.zhihu.com/p/420560153

    Java中锁的实现方式有两种:synchronized关键字和并发包中的锁类。synchronized这个同步关键字以前性能不是太理想,在随着不停的优化后,它已经成了同步的首选。

    锁涉及的几个重要概念:重入锁、自旋锁、锁偏向、锁粗化、公平锁与非公平锁、轻量级锁与重量级锁、读写锁与独占锁(乐观锁与悲观锁)

    synchronized、ReentrantLock 都属于可重入锁。

    synchronized、ReentrantLock 都是悲观锁。

    synchronized,ReentrantLock 都是独占锁。

    synchronized 是重量锁。

    synchronized 是非公平锁,ReentrantLock可以通过构造函数指定该锁是公平的还是非公平的,默认是非公平的。

    问题1: 可重入锁如果加了两把,但是只释放了一把会出现什么问题?

    答:程序卡死,线程不能出来,也就是说我们申请了几把锁,就需要释放几把锁。

    问题2: 如果只加了一把锁,释放两次会出现什么问题?

    答:会报错,java.lang.IllegalMonitorStateException。

    CountDownLatch 与 CyclicBarrier

    CountDownLatch 它是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

    CyclicBarrier 也是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。

    类锁和对象锁(重要)

    Class A {
         // ==>对象锁:普通实例方法默认同步监视器就是this,
         // 即调用该方法的对象
         public synchronized methodA() {
         }

        public  methodB() {    
             // ==>对象锁:this表示是对象锁
             synchronized(this){ 
             }
         }

        // ==>类锁:修饰静态方法
         public static synchronized methodC() {
         }

        public methodD(){
             // ==>类锁:A.class说明是类锁
             synchronized(A.class){}
         }

        // 普通方法:任何情况下调用时,都不会发生竞争
         public common(){
         }
    }

     

    类锁的5种形式

    Class A {
         // 普通字符串属性
         private String val;
         // 静态属性
         private static Object staticObj;

         // ==>类锁情况1:synchronized修饰静态方法
         public static synchronized methodA() {
         }

        public methodB(){
             // ==>类锁情况2:同步块里的对象是类
             synchronized(A.class){}
         }

         public methodC(){
              // ==>类锁情况3:同步块里的对象是字符串
             synchronized("ABC"){}
         }

        public methodD(){
             // ==>类锁情况4:同步块里的对象是静态属性
             synchronized(staticObj){}
         }

        public methodE(){
             // ==>类锁情况5:同步块里的对象是字符串属性
             synchronized(val){}
         }
    }

    锁粗化也提醒了我们平时写代码时,尽量不要在循环内使用锁:

    // 粗化前
    for(int i=0;i<10000;i++){
         // 这会导致频繁同步代码,无谓的消耗系统资源
         synchronized(monitor){
             doSomething...
         }
    }
    // 粗化后
    synchronized(monitor){
         for(int i=0;i<10000;i++){   
             doSomething...
         }
    }

     

    锁偏向

    偏向锁指的是,当第一个线程请求时,会判断锁的对象头里的ThreadId字段的值,如果为空,则让该线程持有偏向锁,并将ThreadId的值置为当前线程ID。当前线程再次进入时,如果线程ID与ThreadId的值相等,则该线程就不会再重复获取锁了。因为锁的请求与释放是要消耗系统资源的。

    如果有其他线程也来请求该锁,则偏向锁就会撤销,然后升级为轻量级锁。如果锁的竞争十分激烈,则轻量级锁又会升级为重量级锁。

     

     

     

  • 相关阅读:
    PAT 1065. A+B and C (64bit) (20)
    PAT 1042. Shuffling Machine (20)
    PAT 1001. A+B Format (20)
    HDU 2082 找单词 母函数
    NYOJ 138 找球号(二) bitset 二进制的妙用
    POJ 1151 Wormholes spfa+反向建边+负环判断+链式前向星
    POJ 1511 Invitation Cards 链式前向星+spfa+反向建边
    zzuli 2130: hipercijevi 链式前向星+BFS+输入输出外挂
    NYOJ 323 Drainage Ditches 网络流 FF 练手
    POJ 1273 Drainage Ditches 网络流 FF
  • 原文地址:https://www.cnblogs.com/zhaoguan_wang/p/15996598.html
Copyright © 2020-2023  润新知