并发学习13--多线程ReentrantLock

  • ReentrantLock特点:

1.可中断

2.可设置超时时间:超过设置时间就取消竞争资源

3.可设置为公平锁:先进先出,先等待的优先获得锁

4.支持多个条件变量

  • 与Synchronized相同点:

都支持可重入

基本语法:
//获取锁
reentrantLock.lock()
try{
    //临界区
}finally{
    //释放锁
    reentrantLock.unlock();
}
可重入:

如果一个线程获得了一个锁,那么它可以再次获得这个锁;

不可重入:如果一个线程获得了一个锁,当他再次获得这个锁时会被自己挡住。因为它已经有这个锁了。

ReentrantLock特性示范:
lock的可重入:
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;
@Slf4j(topic = "TC13")
public class TC13 {
    private static ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {

        lock.lock();
        try {
            log.debug("enter main.");
            m1();
        }finally {
            lock.unlock();
        }
    }

    private static void m1() {
        lock.lock();
        try {
            log.debug("enter m1.");
            m2();
        }finally {
            lock.unlock();
        }
    }

    private static void m2(){
        lock.lock();
        try {
            log.debug("enter m2.");
        }finally {
            lock.unlock();
        }
    }
}
lock的可中断:
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

@Slf4j(topic = "TC14")
public class TC14 {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                log.debug("尝试获得锁");
                //lockInterruptibly 可被打断
                //如果没有竞争,此方法可以获得lock对象锁。
                //如果有竞争,那么就会进入阻塞队列,可以用interrupt()中断等待
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
                log.debug("t1被打断");
                return;
            }
            try {
                log.debug("获得锁");
            } finally {
                lock.unlock();
            }
        }, "t1");

        lock.lock();
        //主线程已经调用了lock对象锁,t1线程调用lockInterruptibly()时会产生竞争,所以t1线程进入阻塞队列。
        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //中断t1线程的阻塞等待状态。抛出InterruptedException异常。
        t1.interrupt();
    }
}
锁超时:
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j(topic = "TC15")
public class TC15 {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                //超过等待时间就是设置获取锁为false
                if (!lock.tryLock(2, TimeUnit.SECONDS)) {
                    log.debug("t1获取锁失败");
                    return;
                }
            }catch (InterruptedException e) {
                //线程被中断异常
                e.printStackTrace();
                log.debug("t1被中断");
                return;
            }
            try {
                log.debug("t1获取锁成功");
            } finally {
                lock.unlock();
                log.debug("t1释放锁");
            }

        }, "t1");

        log.debug("main获取到锁");
        lock.lock();
        //开始计算t1获取锁对象时间
        t1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //main 1秒后释放,t1等待2秒,故t1能等到锁对象
        lock.unlock();
        log.debug("main释放锁");
    }
}
使用ReentrantLock解决科学家就餐问题:
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

public class TC16 {
    public static void main(String[] args) {
        ChopstickTest chopstickTest1 = new ChopstickTest(1);
        ChopstickTest chopstickTest2 = new ChopstickTest(2);
        ChopstickTest chopstickTest3 = new ChopstickTest(3);
        ChopstickTest chopstickTest4 = new ChopstickTest(4);
        ChopstickTest chopstickTest5 = new ChopstickTest(5);


        Philosopher philosopher1 = new Philosopher("科学家1",chopstickTest1,chopstickTest2);
        Philosopher philosopher2 = new Philosopher("科学家2",chopstickTest2,chopstickTest3);
        Philosopher philosopher3 = new Philosopher("科学家3",chopstickTest3,chopstickTest4);
        Philosopher philosopher4 = new Philosopher("科学家4",chopstickTest4,chopstickTest5);
        Philosopher philosopher5 = new Philosopher("科学家5",chopstickTest5,chopstickTest1);

        philosopher1.start();
        philosopher2.start();
        philosopher3.start();
        philosopher4.start();
        philosopher5.start();

    }
}
@Slf4j(topic = "Philosopher")
class Philosopher extends Thread{
    ChopstickTest left;
    ChopstickTest right;
    private String name;

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

    @Override
    public void run() {
        //让其一直吃饭,检查死锁问题不会复现
        while(true) {
            if (left.tryLock()) {
                try{
                    //若右手筷处于竞争状态,那么该科学家拿右手筷false,不进入if判断,直接执行left的finally,释放左手筷
                    //让其他科学家能够拿该科学家的左手筷
                    if (right.tryLock()) {
                        try {
                            eat(name);
                        }finally {
                            right.unlock();
                        }
                    }
                }finally {
                    left.unlock();
                }
            }
        }

    }

    private void eat(String name) {
        log.debug(name+"吃上饭了");
    }
}

class ChopstickTest extends ReentrantLock {
    private int id;

    public ChopstickTest(int id) {
        this.id=id;
    }
}
公平锁:

在ReentrantLock的构造方法里有一个Boolean参数可设置公平锁,默认是false为不公平.

条件变量:

import lombok.extern.slf4j.Slf4j;
import sun.misc.ConditionLock;

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

@Slf4j(topic="TC17")
public class TC17 {
    static boolean hasCigarate = false;
    static boolean hasTakeOut = false;

    static ReentrantLock lock = new ReentrantLock();

    static Condition waitCigarate = lock.newCondition();
    static Condition waitTakeOut = lock.newCondition();
    public static void main(String[] args) {
        new Thread(()->{
            lock.lock();
            try {
                log.debug("有烟没[{}]",hasCigarate);
                while (!hasCigarate) {
                    log.debug("没烟再等会");
                    try {
                        waitCigarate.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (hasCigarate) {
                    log.debug("有烟了,开始干活");
                }else{
                    log.debug("没干成活");
                }
            }finally {
                lock.unlock();
            }
        },"小南").start();

        new Thread(()->{
            lock.lock();
            try {
                log.debug("有外卖没[{}]",hasTakeOut);
                while (!hasTakeOut) {
                    log.debug("没外卖再等会");
                    try {
                        waitTakeOut.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (hasTakeOut) {
                    log.debug("有外卖了,开始看电视");
                }else{
                    log.debug("没看成电视");
                }
            }finally {
                lock.unlock();
            }
        },"小丽").start();

        new Thread(()->{
            lock.lock();
            try {
                while (!hasCigarate) {
                    log.debug("开始送烟");
                    hasCigarate = true;
                    //唤醒waitCigarate.await()
                    waitCigarate.signal();
                }
            }finally {
                lock.unlock();
            }
        },"送烟的").start();

        new Thread(()->{
            lock.lock();
            try {
                while (!hasTakeOut) {
                    log.debug("开始送外卖");
                    hasTakeOut = true;
                    waitTakeOut.signal();
                }
            }finally {
                lock.unlock();
            }
        },"送外卖的").start();
    }
}

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值