简体   繁体   English

java中线程通信的Lock和Condition

[英]Lock and Condition about thread communication in java

I'm a java beginner and I write below code while learning Thread in java.我是一名 Java 初学者,我在学习 Java Thread编写了以下代码。 I think, if I lock in Resource.set() and comment out the Lock.unlock() , the code in Resource.out() can't be executed because I can't unlock in when I want to execute out method.我认为,如果我锁定Resource.set()并注释掉Lock.unlock() ,则Resource.out()的代码无法执行,因为我在想要执行 out 方法时无法解锁。 BTW, whether I comment out the unlock in the set() or in out() , the program will execute in this way:顺便说一句,无论我在set()还是out()注释掉解锁,程序都会以这种方式执行:

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

I think a long time and don't understand about it.想了很久,还是不明白。 I just learned it, maybe I have a wrong understanding,so I hope someone's help.刚学的,可能理解有误,希望各位大侠指教。 Please forgive my poor English.请原谅我糟糕的英语。 Thank you very much.非常感谢。 My code is here:我的代码在这里:

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();
            }
        }
    }
  }
}

In both producer and consumer, you are calling lock.await repeatly by在生产者和消费者中,您都通过lock.await重复调用lock.await

while (true) {
    //
}

From the doc , when you call lock.await :文档中,当您调用lock.await

The lock associated with this Condition is atomically released与此 Condition 关联的锁被自动释放

So, whether you comment out lock.unlock or not, both producer and consumer will not be blocked.所以,不管你是否注释掉lock.unlock ,生产者和消费者都不会被阻塞。

PS Use below code to log more details about getting and releasing lock: PS使用以下代码记录有关获取和释放锁的更多详细信息:

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();
            }
        }
    }
  }
}

FirstOfAll, "if I lock in Resource.set() and comment out the Lock.unlock(), the code in Resource.out() can't be executed ".首先,“如果我在 Resource.set() 中锁定并注释掉 Lock.unlock(),则 Resource.out() 中的代码将无法执行”。 This statement of yours is wrong.你的这个说法是错误的。

Let me clarify why,让我澄清为什么,

In your posted code, where out() has no unlock.在您发布的代码中, out()没有解锁。 I assume you have no problem that one of the Consumer threads ( t2 or t3 ) have no problem in acquiring the lock.我假设您没有问题, Consumer线程之一( t2t3 )在获取锁时没有问题。

So lets say t2 acquired the lock, while entering out() method and didn't release the lock while exiting out() method.因此,假设t2在进入out()方法时获取了锁,并且在退出out()方法时没有释放锁。 But you overlooked the fact that out() method is executed in infinite loop inside run() method of Consumer Runnable.但是您忽略了out()方法在Consumer Runnable 的run()方法内无限循环执行的事实。 So when t2 exits out() , sleep of 500 milliseconds;所以当t2退出out() ,休眠500毫秒; its still in possession of the lock.它仍然拥有锁。 When it enters the out() method in its next iteration, it executes Lock.lock() on the same lock it already has.当它在下一次迭代中进入out()方法时,它会在它已经拥有的同一个锁上执行Lock.lock() Since the lock is Reentrant Lock, it proceeds and executes await() where it releases the lock;由于锁是Reentrant锁,所以它继续执行await() ,在那里释放锁; and the other threads( Producer threads) waiting on the lock gets chance to acquire the lock.等待锁的其他线程( Producer线程)有机会获得锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM