美文网首页
并发编程(十):ReentrantLock

并发编程(十):ReentrantLock

作者: codeMover | 来源:发表于2020-04-18 11:31 被阅读0次

ReentrantLock特性

  • 可中断
  • 可以设置超时时间
  • 可以设置公平锁
  • 支持多个条件变量
  • 支持重入,和synchronized一致

基本语法

// 基于ReentrantLock对象保护临界区
reentarntLock.lock();
try{
    // 临界区
}finally{
    // rnnetrantLock.unlock();
}

可重入

  • 可重入指同一线程如果首次获得了这把锁,如果在获取再获取这把锁,表示可重入

可打断

  • lockInterruptibly() 锁可打断
    • 如果没有竞争,就会获取lock对象锁
    • 如果有竞争就会进入阻塞队列
    • 可以被其他线程用interrupt方法打断

锁超时

  • tryLock() 尝试获得锁
  • 使用tryLock()解决哲学家就餐问题,tryLock()返回false说明没能获得锁
public class PhilosopherProblem {
    public static void main(String[] args) {
        Chopstic c1 = new Chopstic("1");
        Chopstic c2 = new Chopstic("2");
        Chopstic c3 = new Chopstic("3");
        Chopstic c4 = new Chopstic("4");
        Chopstic c5 = new Chopstic("5");

        new Philosopher("苏格拉底",c1,c2).start();
        new Philosopher("泊拉图",c2,c3).start();
        new Philosopher("亚里士多德",c3,c4).start();
        new Philosopher("阿基米德",c4,c5).start();
        new Philosopher("米开朗琪罗",c5,c1).start();
    }
}

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

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

    @SneakyThrows
    @Override
    public void run() {
        while (true){
//            synchronized (left){
//                synchronized (right){
//                    eat();
//                }
//            }
            if(left.tryLock()){
                try{
                    if(right.tryLock()){
                        try{
                            eat();
                        }finally {
                            right.unlock();
                        }
                    }
                }finally {
                    left.unlock();
                }
            }
        }
    }
    private void eat() throws InterruptedException {
        log.debug("eating...");
        Thread.sleep(1000);
    }
}


class Chopstic extends ReentrantLock {
    private String name;
    public Chopstic(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return "筷子:【"+name+"】";
    }
}

公平锁

  • ReentrantLock默认是非公平锁,当构造函数时true,使用公平锁
  • 公平锁可以解决姐问题
  • 平时不设置,公平锁降低并发度

条件变量

ReentrantLock支持多个条件变量,想比synchronized的waitset

  • synchronized不满足条件的变量都会放在同一个waitset中
  • ReentrantLock中的条件变量支持多个条件变量,一个条件变量想当与一个waitset
  • 使用流程
    • await前需要获得锁
    • await执行后,会释放锁,进入conditionObject等待
    • await的线程被唤醒singnal(打断、超时)时重新竞争lock锁
    • 竞争lock锁成功后,从await后继续执行
@Slf4j(topic = "ants.ManyCondition")
public class ManyCondition {
    static volatile boolean t1Status;
    static volatile boolean t2Status;
    static ReentrantLock lock = new ReentrantLock();
    static Condition sta1 = lock.newCondition();
    static Condition sta2 = lock.newCondition();

    public static void main(String[] args) {
        new Thread("t1") {
            @SneakyThrows
            @Override
            public void run() {
                lock.lock();
                try {
                    while (!t1Status) {
                        sta1.await();
                    }
                    log.debug("t1干了剩下的活");
                } finally {
                    lock.unlock();
                }

            }
        }.start();
        new Thread("t2") {
            @SneakyThrows
            @Override
            public void run() {
                lock.lock();
                try {
                    while (!t2Status) {
                        sta2.await();
                    }
                    log.debug("t2干了剩下的活");
                } finally {
                    lock.unlock();
                }
            }
        }.start();
        lock.lock();
        try {
            sta1.signal();
            t1Status = true;
        } finally {
            lock.unlock();

        }
    }
}

相关文章

网友评论

      本文标题:并发编程(十):ReentrantLock

      本文链接:https://www.haomeiwen.com/subject/znzmvhtx.html