将ReentrantLock与多个线程一起使用

我是多线程的新手,非常感谢您的帮助。

编辑后的代码和问题

我想使用ReentrantLock类来控制对两个ArrayList的访问。第一个是orderList,第二个是prepareOrders ArrayList。 Class Chef(扩展了Thread)的两个对象每次都希望从数组列表中删除订单,休眠一段随机的时间,然后将订单放置在prepareOrders数组列表中,直到OrdersList为空。这是我当前的代码:

厨师班

import java.util.concurrent.locks.ReentrantLock;

public class Chef extends Thread{

    private String name;
    private ReentrantLock orderLock; 
    private ReentrantLock preparedLock;
    private String orderName;
    private Object useForLocking = new Object();

    public Chef(String name,ReentrantLock orderLock,ReentrantLock preparedLock){
        this.name = name;
        this.orderLock = orderLock; 
        this.preparedLock = preparedLock;
    }

    public void run(){
        while(Restaurant.orderList.size()>0){
            try{
                getOrder();
                System.out.println(name +" is preparing "+orderName+"\n");
                Thread.sleep(Math.round(Math.random()*100));
                outputOrder();
            }catch(Exception e){
                System.out.println("run exception: "+e+"\n");
            }
        }
    }

    public void getOrder(){
        if(orderLock.tryLock()){
            orderLock.lock();
            try{
                orderName = Restaurant.orderList.remove(0);
            }catch(Exception e){
                System.out.println("getOrder exception: "+e+"\n");
            }finally{
                orderLock.unlock();
                synchronized (useForLocking){
                    useForLocking.notify();
                }
            }
        }else{
            try{
                synchronized (useForLocking){
                    useForLocking.wait();
                }
            }catch(Exception e){
                System.out.println("getOrder wait exception: "+e+"\n");
            }
        }
    }

    public void outputOrder(){
        if(preparedLock.tryLock()){
            preparedLock.lock();
            try{
                Restaurant.preparedOrders.add(orderName);
            }catch(Exception e){
                System.out.println("outputOrder exception: "+e+"\n");
            }finally{
                preparedLock.unlock();
                synchronized (useForLocking){
                    useForLocking.notify();
                }
            }
        }else{
            try{
                synchronized (useForLocking){
                    useForLocking.wait();
                }
            }catch(Exception e){
                System.out.println("outputOrder wait exception: "+e+"\n");
            }
        }
    }
}

餐厅课(主)

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

 public class Restaurant{
    public static ArrayList<String> orderList = new ArrayList<String>();
    public static ArrayList<String> preparedOrders = new ArrayList<String>();

    public static void main(String[] args) {

        orderList.add("Cheese Pizza");
        orderList.add("Hotdog");
        orderList.add("Hamburger");
        orderList.add("Cheese burger");
        orderList.add("Chicken Nuggets");
        orderList.add("Chicken Burger");

        ReentrantLock orderLock = new ReentrantLock();
        ReentrantLock preparedLock = new ReentrantLock();

        Chef c1 = new Chef("Chef John",orderLock,preparedLock);
        Chef c2 = new Chef("Chef Mark",preparedLock);

        c1.start();
        c2.start();
    }
 }

输出

Chef John is preparing Cheese Pizza
Chef John is preparing Hotdog
Chef John is preparing Hamburger
Chef John is preparing Cheese burger
Chef John is preparing Chicken Nuggets
Chef John is preparing Chicken Burger

为什么第一个线程未解锁?

xiangxiangdetang 回答:将ReentrantLock与多个线程一起使用

似乎您的方法每个都将互斥量锁定两次,但仅将其解锁一次。他们这样做:

if(preparedLock.tryLock()) {   // locks the mutex if the result is true.
    preparedLock.lock();       // This locks it A SECOND TIME.
    try{
        ...
    }finally{
        preparedLock.unlock(); // This unlocks it ONCE.
    }
}
// At this point,the thread still has one lock on preparedLock

ReentrantLock对象允许单个线程在互斥量上保留多个声明。对于这样的情景很有用:

private final Lock myMutex = new ReentrantLock();

public void foobar(...) {
    myMutex.lock();
    try {
        ...
    }
    finally {
        myMutex.unlock();
    }
}

public void bizzwizz(...) {
    myMutex.lock();
    try {
        ...
        foobar(...);
        ...
    }
    finally {
        myMutex.unlock();
    }
}

foobar()和bizzwizz()都是公共函数。我们希望其他类能够调用其中一个,但是我们也希望它们都锁定myMutex,并且我们希望bizzwizz()能够调用foobar()。>

如果myMutex不是可重入的,则bizzwizz()调用foobar()时会遇到问题,因为foobar()会尝试锁定已经被锁定的互斥量。通常发生的情况是,lock()调用只有在拥有它的线程释放锁之后才会返回。但这永远不会发生,因为拥有它的同一个线程正在调用lock()。这种情况有时称为自我死锁

可重入互斥锁允许单个线程对该互斥锁具有多个声明。每个lock()调用都会将声明的数量增加1,每个unlock()调用都会将其减少。只要线程A至少拥有 个声明,线程B,C和D将无法lock()互斥体。

,

这不是您问题的答案。我不确定您的问题是什么,但这是您应该知道的。

如果要使用Lock对象,请按以下方式使用它们:

myLock.lock();
try {
    doSomethingThatNeedsProtection();
}
finally {
    myLock.unlock();
}

此模式可确保无论发生任何其他情况,代码始终将myLock保持解锁状态。要点是:

  • lock()调用不在try { ... } finally { ... }语句之外。通常,我们不期望lock()调用会抛出异常,但是如果 did 抛出异常,随后尝试对其进行解锁将是一个错误。

  • lock()调用和try之间没有其他东西。 lock()成功返回后,我们要确保不会抛出将绕过Exception子句的Errorfinally {...}

  • unlock()调用位于finally {...}内部。这样可以确保无论发生什么其他情况,此代码段都将使锁处于解锁状态。

本文链接:https://www.f2er.com/3134817.html

大家都在问