• synchronized 和 Lock 的区别


    • 原始结构
      • synchronized 是关键字属于 JVM 层面,反应在字节码上是 monitorenter 和 monitorexit,其底层是通过 monitor 对象来完成,wait/notify 等方法也是依赖 monitor 对象,只有在同步块或方法中才能调用 wait/notify 等方法
      • Lock 是具体类(java.util.concurrent.locks.Lock),是 api 层面的锁
    • 使用方法
      • synchronized 不需要用户手动去释放锁,当 synchronized 代码执行完后系统会自动让线程释放对锁的占用
      • ReentrantLock 则需要用户手动的释放锁,若没有主动释放锁,可能导致出现死锁的现象,lock() 和 unlock() 方法需要配合 try/finally 语句来完成
    • 等待是否可中断
      • synchronized 不可中断,除非抛出异常或者正常运行完成。
      • ReentrantLock 可中断,设置超时方法 tryLock(long timeout, TimeUnit unit) 或者代码中调用 lockInterruptibly 方法中断
    • 加锁是否公平
      • synchronized 非公平锁
      • ReentrantLock 默认非公平锁,构造方法中可以传入 boolean 值,true 为公平锁,false 为非公平锁
    • 精确唤醒
      • synchronized 没有 Condition,要么随机唤醒一个线程要么唤醒全部线程
      • ReentrantLock 用来实现分组唤醒需要唤醒的线程们,可以精确唤醒
    /**
     * @author LiuHuan
     * @date 2020-06-17 15:52
     * @desc Lock精确唤醒:A线程打印5次之后唤醒B线程打印10次之后唤醒C线程打印15次,之后再唤醒A,重复3轮
     */
    public class ConditionTest {
    
        public static void main(String[] args) {
            ShareResource shareResource = new ShareResource();
    
            new Thread(() -> {
                for (int i = 0; i < 3; i++) {
                    shareResource.print5();
                }
            }, "A").start();
    
            new Thread(() -> {
                for (int i = 0; i < 3; i++) {
                    shareResource.print10();
                }
            }, "B").start();
    
            new Thread(() -> {
                for (int i = 0; i < 3; i++) {
                    shareResource.print15();
                }
            }, "C").start();
        }
    
    
    }
    
    class ShareResource {
        // A 1   B 2   c 3
        private int number = 1;
        // 创建一个重入锁
        private Lock lock = new ReentrantLock();
    
        // 这三个相当于备用钥匙
        private Condition condition1 = lock.newCondition();
        private Condition condition2 = lock.newCondition();
        private Condition condition3 = lock.newCondition();
    
    
        public void print5() {
            lock.lock();
            try {
                // 判断
                while(number != 1) {
                    condition1.await();
                }
    
                // 干活
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + "	 " + number + "	" + i);
                }
    
                // 唤醒 (干完活后,需要通知B线程执行)
                number = 2;
                // 通知2号去干活了
                condition2.signal();
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void print10() {
            lock.lock();
            try {
                // 判断
                while(number != 2) {
                    // 不等于1,需要等待
                    condition2.await();
                }
    
                // 干活
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "	 " + number + "	" + i);
                }
    
                // 唤醒 (干完活后,需要通知C线程执行)
                number = 3;
                // 通知2号去干活了
                condition3.signal();
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void print15() {
            lock.lock();
            try {
                // 判断
                while(number != 3) {
                    // 不等于1,需要等待
                    condition3.await();
                }
    
                // 干活
                for (int i = 0; i < 15; i++) {
                    System.out.println(Thread.currentThread().getName() + "	 " + number + "	" + i);
                }
    
                // 唤醒 (干完活后,需要通知C线程执行)
                number = 1;
                // 通知1号去干活了
                condition1.signal();
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    输出:
    
    A     1    0
    A     1    1
    A     1    2
    A     1    3
    A     1    4
    B     2    0
    B     2    1
    B     2    2
    B     2    3
    B     2    4
    B     2    5
    B     2    6
    B     2    7
    B     2    8
    B     2    9
    C     3    0
    C     3    1
    C     3    2
    C     3    3
    C     3    4
    C     3    5
    C     3    6
    C     3    7
    C     3    8
    C     3    9
    C     3    10
    C     3    11
    C     3    12
    C     3    13
    C     3    14
    A     1    0
    A     1    1
    A     1    2
    A     1    3
    A     1    4
    B     2    0
    B     2    1
    B     2    2
    B     2    3
    B     2    4
    B     2    5
    B     2    6
    B     2    7
    B     2    8
    B     2    9
    C     3    0
    C     3    1
    C     3    2
    C     3    3
    C     3    4
    C     3    5
    C     3    6
    C     3    7
    C     3    8
    C     3    9
    C     3    10
    C     3    11
    C     3    12
    C     3    13
    C     3    14
    A     1    0
    A     1    1
    A     1    2
    A     1    3
    A     1    4
    B     2    0
    B     2    1
    B     2    2
    B     2    3
    B     2    4
    B     2    5
    B     2    6
    B     2    7
    B     2    8
    B     2    9
    C     3    0
    C     3    1
    C     3    2
    C     3    3
    C     3    4
    C     3    5
    C     3    6
    C     3    7
    C     3    8
    C     3    9
    C     3    10
    C     3    11
    C     3    12
    C     3    13
    C     3    14
  • 相关阅读:
    Git合并
    Git对象
    Git储藏和引用日志
    小小c#算法题 4 子数组最大和
    小小c#算法题 2 求素数
    小小c#算法题 5 插入排序
    小小c#算法题 1 找出数组中满足条件的两个数
    [转] WPF – Editing Mode with Save and Cancel Capability
    小小c#算法题 0 单循环冒泡排序
    小小c#算法题 3 字符串语句反转
  • 原文地址:https://www.cnblogs.com/ding-dang/p/13162972.html
Copyright © 2020-2023  润新知