【问题标题】:Lock and Condition about thread communication in javajava中关于线程通信的锁和条件
【发布时间】:2018-02-20 06:52:16
【问题描述】:

我是一名 java 初学者,我在学习 java 中的 Thread 时编写了以下代码。我认为,如果我锁定Resource.set() 并注释掉Lock.unlock(),则Resource.out() 中的代码无法执行,因为当我想执行out 方法时无法解锁。 BTW,不管我在set()还是out()注释掉解锁,程序都会这样执行:

Thread[Thread-1,5,main]....生产....chicken1
Thread[Thread-2,5,main]....消费..........chicken1
Thread[Thread-0,5,main]....生产....chicken2
Thread[Thread-3,5,main]....消费..........chicken2 ......

我想了很久,还是不明白。刚学,可能理解有误,望高人指教。 请原谅我糟糕的英语。非常感谢。我的代码在这里:

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

public class ThreadStudying {

public static void main(String[] args) {
    Resource r = new Resource();
    Thread t0 = new Thread(new Producer(r));
    Thread t1 = new Thread(new Producer(r));
    Thread t2 = new Thread(new Consumer(r));
    Thread t3 = new Thread(new Consumer(r));

    t0.start();
    t1.start();
    t2.start();
    t3.start();
}

static class Resource {
    private String name;
    private int count = 1;
    boolean isOut = false;

    Lock lock = new ReentrantLock();
    Condition pro_con = lock.newCondition();
    Condition consu_con = lock.newCondition();

    public void set(String name) {
        lock.lock();
        try {
            while (isOut) {
                try {
                    pro_con.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            this.name = name + count;
            System.out.println(Thread.currentThread() + "....Produce...." + this.name);
            count++;

            isOut = true;
            consu_con.signal();
        }
        finally {
            lock.unlock();
        }
    }

    public void out() {
        lock.lock();
        try {
            while (!isOut) {
                try {
                    consu_con.await();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(Thread.currentThread() + "....Consume.........." + this.name);

            isOut = false;
            pro_con.signal();
        }
        finally {
            //lock.unlock();
        }
    }
}

static class Producer implements Runnable {
    Resource r;

    Producer(Resource r) {
        this.r = r;
    }

    public void run() {
        while (true) {
            r.set("chicken");

            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

static class Consumer implements Runnable {
    Resource r;

    Consumer(Resource r) {
        this.r = r;
    }


    @Override
    public void run() {
        while (true) {
            r.out();
            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
  }
}

【问题讨论】:

    标签: java multithreading locking java-threads


    【解决方案1】:

    在生产者和消费者中,您都在重复调用lock.await

    while (true) {
        //
    }
    

    来自doc,当您拨打lock.await时:

    与此条件关联的锁被原子释放

    所以,无论你是否注释掉lock.unlock,生产者和消费者都不会被阻塞。

    P.S. 使用以下代码记录有关获取和释放锁的更多详细信息:

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class ThreadStudying {
    
    public static void main(String[] args) {
        Resource r = new Resource();
        Thread t0 = new Thread(new Producer(r), "Producer 1");
        Thread t1 = new Thread(new Producer(r), "Producer 2");
        Thread t2 = new Thread(new Consumer(r), "Consumer 1");
        Thread t3 = new Thread(new Consumer(r), "Consumer 2");
    
        t0.start();
        t1.start();
        t2.start();
        t3.start();
    }
    
    static class Resource {
        private String name;
        private int count = 1;
        boolean isOut = false;
    
        Lock lock = new ReentrantLock();
        Condition pro_con = lock.newCondition();
        Condition consu_con = lock.newCondition();
    
        public void set(String name) {
            System.out.println(Thread.currentThread() + "before lock");
            lock.lock();
            System.out.println(Thread.currentThread() + "get lock");
            try {
                while (isOut) {
                    try {
                        System.out.println(Thread.currentThread() + "release lock");
                        pro_con.await();
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                this.name = name + count;
                System.out.println(Thread.currentThread() + "....Produce...." + this.name);
                count++;
    
                isOut = true;
                consu_con.signal();
            }
            finally {
    
            }
        }
    
        public void out() {
            System.out.println(Thread.currentThread() + "before lock");
            lock.lock();
            System.out.println(Thread.currentThread() + "get lock");
            try {
                while (!isOut) {
                    try {
                        System.out.println(Thread.currentThread() + "release lock");
                        consu_con.await();
                    }
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                System.out.println(Thread.currentThread() + "....Consume.........." + this.name);
    
                isOut = false;
                pro_con.signal();
            }
            finally {
                //lock.unlock();
            }
        }
    }
    
    static class Producer implements Runnable {
        Resource r;
    
        Producer(Resource r) {
            this.r = r;
        }
    
        public void run() {
            while (true) {
                r.set("chicken");
    
                try {
                    Thread.sleep(500);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    static class Consumer implements Runnable {
        Resource r;
    
        Consumer(Resource r) {
            this.r = r;
        }
    
    
        @Override
        public void run() {
            while (true) {
                r.out();
                try {
                    Thread.sleep(500);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
      }
    }
    

    【讨论】:

      【解决方案2】:

      FirstOfAll,“如果我锁定 Resource.set() 并注释掉 Lock.unlock(),Resource.out() 中的代码将无法执行”。你的这种说法是错误的。

      让我解释一下原因,

      在您发布的代码中,out() 没有解锁。我假设您认为Consumer 线程之一(t2t3)在获取锁时没有问题。

      假设t2 在进入out() 方法时获得了锁,而在退出out() 方法时没有释放锁。但是您忽略了out() 方法在run() 方法的Consumer Runnable 内无限循环执行的事实。所以当t2退出out()时,休眠500毫秒;它仍然拥有锁。当它在下一次迭代中进入out() 方法时,它会在它已经拥有的同一个锁上执行Lock.lock()。由于锁是ReentrantLock,它继续执行await(),在那里它释放锁;等待锁的其他线程(Producer线程)有机会获得锁。

      【讨论】:

        猜你喜欢
        • 2015-08-13
        • 2017-05-17
        • 2015-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-22
        • 2011-04-13
        • 2015-11-04
        相关资源
        最近更新 更多