java_锁_synchronized与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 time,TimeUnit unit)

    2、当通过lockInterruptibly();进行加锁时,线程可通过调用interrupt();方法进行中断:

    (lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果其他线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。

    也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有等待,

    那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。【注意是:等待的那个线程B可以被中断,不是正在执行的A线程被中断】)

 

4、加锁是否公平

  synchronized:非公平锁

  ReentrantLock:两者都可以,默认是非公平锁,构造方法可以传入boolean类型的值,true:公平锁,false:非公平锁;

 

5、锁绑定多个条件Condition

  synchronized:没有

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

 

编程题:(ReentrantLock绑定多个条件Condition,实现精确唤醒)

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

/**
 * 多线程之间按顺序调用
 * 实现A-->B-->C三个线程启动
 * A打印5次,B打印10次,C打印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();

    /**
     *
     * @param str 当前调用的线程
     * @param index 打印次数
     */
    public void print(String str,Integer index) {
        lock.lock();//加锁
        try {
            if (str.equals("A")){
                //1、判断
                while (number != 1) {//当前不是 1(A),c1进行等待,则应该是 2(B)干活
                    c1.await();
                }
            }else if (str.equals("B")){
                while (number != 2) {//当前不是 2(B),c2进行等待,则应该是 3(C)干活
                    c2.await();
                }
            }else if (str.equals("C")){
                while (number != 3) {//当前不是 3(C),c3进行等待,则应该是 1(A)干活
                    c3.await();
                }
            }

            //2、干活
            System.out.print(Thread.currentThread().getName()+"\t");
            for (int i = 1; i <= index; i++) {
                System.out.print("、"+i);
            }
            System.out.println();
            //3、通知(唤醒)
            if (number == 1) {//如果当前是A在执行,则唤醒B
                number = 2;
                c2.signal();
            } else if (number == 2) {//如果当前是B在执行,则唤醒C
                number = 3;
                c3.signal();
            }else if (number == 3){//如果当前是C在执行,则唤醒A
                number = 1;
                c1.signal();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();//解锁
        }
    }

}

public class SynchronizedReentrantLockDemo {
    public static void main(String[] args) {
        ShareResource resource = new ShareResource();
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                resource.print("A",5);
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                resource.print("B",10);
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                resource.print("C",15);
            }
        }, "C").start();
    }
}

posted @ 2021-03-10 09:33  DHaiLin  阅读(268)  评论(0编辑  收藏  举报