synchronized 和 lock 有什么区别?用新的 lock 有什么好处?

1、原始构成

synchronized 是关键字属于 JVM 层面,
           monitorenter(底层是通过 monitor 对象来完成, 其实 wait/notify 等方法也依赖于 monitor 对象只有在同步块或方法中才能调 wait/notify 等方法)
           monitorexit
Lock 是具体类(java.util.concurrent.locks.Lock)是 api 层面的锁

2、使用方法

synchronized 不需要用户去手动释放锁,当 synchronized 代码执行完后系统会自动让线程释放对锁的占用
ReentrantLock 则需要用户去手动释放锁若没有主动释放锁,就有可能导致出现死锁现象。
   需要 lock() 和 unlock() 方法配合 try / finally 语句块来完成。

3、等待是否可中断

synchronized 不可中断,除非抛出异常或者正常运行完成
ReentrantLock 可中断,1、设置超时方法 tryLock(long timeout, TimeUnit unit)
                                       2、lockInterruptibly() 放代码块这,调用 interrupt() 方法可中断

4、加锁是否公平

synchronized 非公平锁
ReentrantLock 两者都可以,默认非公平锁,构造方法可以传入 boolean 值,true 为公平锁,false 为非公平锁

5、锁绑定多个条件 Condition

synchronized 没有
ReentrantLock 用来实现分组唤醒需要唤醒的线程们,可以精神唤醒,而不是像 synchronized 要么随机唤醒一个线程要么唤醒全部线程。

package com.brian.interview.study.thread;

/**
 * Copyright (c) 2020 ZJU All Rights Reserved
 * <p>
 * Project: JavaSomeDemo
 * Package: com.brian.interview.study.thread
 * Version: 1.0
 * <p>
 * Created by Brian on 2020/2/12 23:03
 */

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 题目:synchronized 和 lock 有什么区别?用新的 lock 有什么好处?你举例说说
 * 1、原始构成
 *    synchronized 是关键字属于 JVM 层面,
 *       monitorenter(底层是通过 monitor 对象来完成, 其实 wait/notify 等方法也依赖于 monitor 对象只有在同步块或方法中才能调 wait/notify 等方法)
 *       monitorexit
 *    Lock 是具体类 (java.util.concurrent.locks.Lock) 是 api 层面的锁
 *
 * 2、使用方法
 *    synchronized 不需要用户去手动释放锁, 当 synchronized 代码执行完后系统会自动让线程释放对锁的占用
 *    ReentrantLock 则需要用户去手动释放锁若没有主动释放锁, 就有可能导致出现死锁现象。
 *     需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成。
 *
 * 3、等待是否可中断
 *    synchronized 不可中断, 除非抛出异常或者正常运行完成
 *    ReentrantLock 可中断, 1、设置超时方法 tryLock(long timeout, TimeUnit unit)
 *                         2、lockInterruptibly() 放代码块中, 调用 interrupt() 方法可中断
 *
 * 4、加锁是否公平
 *    synchronized 非公平锁
 *    ReentrantLock 两者都可以, 默认非公平锁, 构造方法可以传入 boolean 值, true 为公平锁, false 为非公平锁
 *
 * 5、锁绑定多个条件 Condition
 *    synchronized 没有
 *    ReentrantLock 用来实现分组唤醒需要唤醒的线程们, 可以精神唤醒, 而不是像 synchronized 要么随机唤醒一个线程要么唤醒全部线程。
 *
 * ===================================================================================================================
 * ===================================================================================================================
 * ===================================================================================================================
 *
 * 题目:多线程之间按顺序调用, 实现 A->B->C 三个线程启动, 要求如下:
 * AA打印5次, BB打印10次, CC打印15次
 * 紧接着
 * AA打印5次, BB打印10次, CC打印15次
 * ......
 * 来10轮
 *
 *
 */

class ShareResource{
    private int number = 1;  // A:1   B:2   C:3
    private Lock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();

    public void print5(){
        lock.lock();
        try {
            // 1、判断
            while(number != 1){
                c1.await();
            }

            // 2、干活
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }

            // 3、通知
            number = 2;
            c2.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print10(){
        lock.lock();
        try {
            // 1、判断
            while(number != 2){
                c2.await();
            }

            // 2、干活
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }

            // 3、通知
            number = 3;
            c3.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print15(){
        lock.lock();
        try {
            // 1、判断
            while(number != 3){
                c3.await();
            }

            // 2、干活
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }

            // 3、通知
            number = 1;
            c1.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

public class SyncAndReentrantLockDemo {
    public static void main(String[] args) {

        ShareResource shareResource = new ShareResource();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print5();
            }
        }, "AA").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print10();
            }
        }, "BB").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                shareResource.print15();
            }
        }, "CC").start();
    }
}
发布了76 篇原创文章 · 获赞 78 · 访问量 4601

猜你喜欢

转载自blog.csdn.net/qq_35340189/article/details/104574838
今日推荐