java 中有关线程通信的锁定和条件
Lock and Condition about thread communication in java
我是 java 初学者,我在 java 中学习 Thread
时编写了以下代码。我想,如果我lock inResource.set()
,注释掉Lock.unlock()
,Resource.out()
里面的代码执行不了,因为我想执行out方法的时候无法unlock in。顺便说一句,无论我在set()
或out()
中注释掉解锁,程序都会这样执行:
Thread[Thread-1,5,main]....Produce....chicken1
Thread[Thread-2,5,main]....Consume..........chicken1
Thread[Thread-0,5,main]....Produce....chicken2
Thread[Thread-3,5,main]....Consume..........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();
}
}
}
}
}
在生产者和消费者中,您通过
重复调用lock.await
while (true) {
//
}
来自 doc,当您调用 lock.await
时:
The lock associated with this Condition is atomically released
所以不管你注释掉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();
}
}
}
}
}
FirstOfAll,"if I lock in Resource.set() and comment out the Lock.unlock(), the code in Resource.out() can't be executed "。你这个说法是错误的。
让我解释一下为什么,
在您发布的代码中,out()
没有解锁。我假设您认为 Consumer
线程之一(t2
或 t3
)在获取锁方面没有问题。
所以假设 t2
在进入 out()
方法时获得了锁,而在退出 out()
方法时没有释放锁。但是你忽略了 out()
方法在 Consumer
Runnable 的 run()
方法内部无限循环执行的事实。所以当t2
退出out()
时,休眠500
毫秒;它仍然拥有锁。当它在下一次迭代中进入 out()
方法时,它会在它已经拥有的同一个锁上执行 Lock.lock()
。由于锁是Reentrant
Lock,所以它会继续执行await()
释放锁的地方;等待锁的其他线程(Producer
个线程)有机会获得锁。
我是 java 初学者,我在 java 中学习 Thread
时编写了以下代码。我想,如果我lock inResource.set()
,注释掉Lock.unlock()
,Resource.out()
里面的代码执行不了,因为我想执行out方法的时候无法unlock in。顺便说一句,无论我在set()
或out()
中注释掉解锁,程序都会这样执行:
Thread[Thread-1,5,main]....Produce....chicken1
Thread[Thread-2,5,main]....Consume..........chicken1
Thread[Thread-0,5,main]....Produce....chicken2
Thread[Thread-3,5,main]....Consume..........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();
}
}
}
}
}
在生产者和消费者中,您通过
重复调用lock.await
while (true) {
//
}
来自 doc,当您调用 lock.await
时:
The lock associated with this Condition is atomically released
所以不管你注释掉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();
}
}
}
}
}
FirstOfAll,"if I lock in Resource.set() and comment out the Lock.unlock(), the code in Resource.out() can't be executed "。你这个说法是错误的。
让我解释一下为什么,
在您发布的代码中,out()
没有解锁。我假设您认为 Consumer
线程之一(t2
或 t3
)在获取锁方面没有问题。
所以假设 t2
在进入 out()
方法时获得了锁,而在退出 out()
方法时没有释放锁。但是你忽略了 out()
方法在 Consumer
Runnable 的 run()
方法内部无限循环执行的事实。所以当t2
退出out()
时,休眠500
毫秒;它仍然拥有锁。当它在下一次迭代中进入 out()
方法时,它会在它已经拥有的同一个锁上执行 Lock.lock()
。由于锁是Reentrant
Lock,所以它会继续执行await()
释放锁的地方;等待锁的其他线程(Producer
个线程)有机会获得锁。