ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并发学习记录07:ReentrantLock

2022-08-22 12:30:21  阅读:226  来源: 互联网

标签:07 lock ReentrantLock Chopstick 并发 debug new public


特点

相比于synchronized,ReentrantLock具有可中断,可以设置超时时间,可以设置为公平锁,支持多个条件变量的特点,它和synchronized一样,都支持可重入

基本语法

// 获取锁
reentrantLock.lock();
try {
 // 临界区
} finally {
 // 释放锁
 reentrantLock.unlock();
}

可重入

可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁,如果是不可重入锁,那么第二次获取锁时,自己也会被挡住

可重入验证代码

@Slf4j(topic = "ch.ReentrantLockTest01")
public class ReentrantLockTest01 {
    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        method1();
    }

    public static void method1() {
        lock.lock();
        try {
            log.debug("method1");
            //验证可重入
            method2();
        } finally {
            lock.unlock();
        }
    }

    public static void method2() {
        lock.lock();
        try {
            log.debug("method2");
            method3();
        } finally {
            lock.unlock();
        }
    }

    public static void method3() {
        lock.lock();
        try {
            log.debug("method3");
        } finally {
            lock.unlock();
        }
    }
}

可打断

可中断锁是指抢占过程可以被中断的锁,如下:

@Slf4j(topic = "ch.ReentrantLockTest02")
public class ReentrantLockTest02 {
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("启动");
            try {
                //可打断的上锁
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.debug("被打断");
                return;
            }
            log.debug("上锁成功");
            lock.unlock();
        }, "t1");

        lock.lock();
        log.debug("获得了锁");
        t1.start();
        Thread.sleep(1);
        log.debug("执行打断");
        t1.interrupt();
        lock.unlock();
    }
}

锁超时

其实这里用了tryLock方法实现了,tryLock有两种使用方法,一种是直接tryLock,返回值是Boolean对象,表示的是用来尝试获取锁,如果成功就返回true,如果失败就返回false,这个方法无论成功失败都会立刻返回。tryLock还有一个重载方法public boolean tryLock(long timeout, TimeUnit unit),表示在这个时间范围内成功获取了锁返回true,没获得就返回false。实例如下:

//测试锁超时
@Slf4j(topic = "ch.ReentrantLockTest03")
public class ReentrantLockTest03 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        Thread t1 = new Thread(() -> {
            log.debug("启动");
            if (!lock.tryLock()) {
                log.debug("获取锁失败,返回");
                return;
            }
            try {
                log.debug("获得了锁");
            } finally {
                lock.unlock();
            }
        }, "t1");
        log.debug("主线程获取了锁");
        lock.lock();
        t1.start();
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

使用tryLock解决哲学家就餐问题

//使用tryLock解决哲学家就餐问题
@Slf4j(topic = "ch.ReentrantLockTest04")
public class ReentrantLockTest04 {
    public static void main(String[] args) {
        Chopstick c1 = new Chopstick("1", true);
        Chopstick c2 = new Chopstick("2", true);
        Chopstick c3 = new Chopstick("3", true);
        Chopstick c4 = new Chopstick("4", true);
        Chopstick c5 = new Chopstick("5", true);
        new Philosopher("哲学家1", c1, c2).start();
        new Philosopher("哲学家2", c2, c3).start();
        new Philosopher("哲学家3", c3, c4).start();
        new Philosopher("哲学家4", c4, c5).start();
        new Philosopher("哲学家5", c5, c1).start();
    }
}

@Slf4j(topic = "ch.Chopstick")
class Chopstick extends ReentrantLock {
    String name;

    public Chopstick(String name, boolean fair) {
        super(fair);
        this.name = name;
    }

    @Override
    public String toString() {
        return "Chopstick{" +
                "name='" + name + '\'' +
                '}';
    }
}

@Slf4j(topic = "ch.Philosopher")
class Philosopher extends Thread {
    Chopstick left;
    Chopstick right;

    public Philosopher(String name, Chopstick left, Chopstick right) {
        super(name);
        this.left = left;
        this.right = right;
    }

    @Override
    public void run() {
        while (true) {
            if (left.tryLock()) {
                try {
                    if (right.tryLock()) {
                        try {
                            eat();
                        } finally {
                            right.unlock();
                        }
                    }
                } finally {
                    left.unlock();
                }
            }
        }
    }

    private void eat() {
        log.debug("eating....");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

公平锁

ReentrantLock 默认是不公平的,公平锁每次获取到锁为同步队列中的第一个节点,保证请求资源时间上的绝对顺序,而非公平锁有可能刚释放锁的线程下次继续获取该锁,则有可能导致其他线程永远无法获取到锁,造成“饥饿”现象。公平锁为了保证时间上的绝对顺序,需要频繁的上下文切换,而非公平锁会降低一定的上下文切换,降低性能开销。因此,ReentrantLock默认选择的是非公平锁,则是为了减少一部分上下文切换,保证了系统更大的吞吐量。

ReentrantLock的两个构造方法:

// 默认非公平
public ReentrantLock() {
  sync = new NonfairSync();
}

// 根据传参来实现公平或非公平锁
public ReentrantLock(boolean fair) {
	sync = fair ? new FairSync() : new NonfairSync();
}

条件变量

synchronized中也有条件变量,起的作用类似于synchronized中的那个waitSet休息室,当条件不满足时,进入waitSet等待

ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比
*synchronized的那些不满足条件的线程都在一间休息室等消息
*而 ReentrantLock 支持多间休息室,可以按照不同的资源等待条件new不同的“休息室”,唤醒时也是按照不同的条件来唤醒的

使用要点:
await前需要获得锁
await执行后,会释放锁,进入conditionObject等待
await线程被唤醒(或打断,或超时)后需重新竞争lock锁
竞争lock锁成功后,从await后继续执行

标签:07,lock,ReentrantLock,Chopstick,并发,debug,new,public
来源: https://www.cnblogs.com/wbstudy/p/16609668.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有