wait()/notify() 无法正常工作
wait()/notify() not working properly
我有一个 ConsumerProducer 对象,我想从两个不同的线程获取它的锁。 class如下:
public class ConsumerProducer {
public String stringPool = null;
public void put(String s){
stringPool = s;
}
public String get(){
String ret = stringPool;
stringPool = null;
return ret;
}
}
线程实现class如下:
public class WaitNotifyTest implements Runnable {
private String threadType;
public ConsumerProducer cp;
public static volatile int i = 1;
public WaitNotifyTest(String threadType, ConsumerProducer cp) {
this.threadType = threadType;
this.cp = cp;
}
public static void main(String[] args) throws InterruptedException {
ConsumerProducer cp = new ConsumerProducer();
WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp);
WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp);
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
t1.join();
t2.join();
}
@Override
public void run() {
while (true) {
if (threadType.equalsIgnoreCase("Consumer")) {
synchronized (cp) {
try {
if (null != cp.get()) {
cp.wait();
}
consume();
System.out.println("notify from Consumer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
synchronized (cp) {
try {
if (null == cp.get()) {
cp.wait();
}
produce();
System.out.println("notify from Producer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (i == 5) {
break;
}
i++;
}
}
public void consume() {
System.out.println("Putting: Counter" + i);
cp.put("Counter" + i);
}
public void produce() {
System.out.println("getting: " + cp.get());
}
}
但是当我 运行 代码时它正面临某种死锁并且它像
一样被卡住打印
Putting: Counter3
notify from Consumer
出现了严重错误,但我无法确定。请帮忙。
您的消费者正在做生产者的工作,而生产者正在做消费者的工作。
交换他们的责任并修改条件等待。请参考下面的代码。
- 消费者会等到什么都拿不到的时候,他就会释放cp的锁。这样生产者就有机会进入同步块。
- 生产者只有在什么都没有的时候才生产,否则他会等待。之后,他就会释放cp的锁。这样消费者就有机会进入同步块。
- 消费者是拿东西的人。
- Producer 是谁把东西放到 table。
- 根据您的评论。你想把计数器从 1 到 5,所以你应该只在生产者线程中添加 i++。如何控制它在两个线程中的增加?
从cp
对象中调用get()
不判断是消费者还是生产者,而是将null赋给stringPool
。这显然是错误的,并且会使消费者从 public space 中获取 null。我添加了一个新方法 clearString()
,只有当消费者消费了产品时,它才会将 public space 设置为 null。
public class WaitNotifyTest implements Runnable {
private String threadType;
public ConsumerProducer cp;
public static volatile int i = 0;
public WaitNotifyTest(String threadType, ConsumerProducer cp) {
this.threadType = threadType;
this.cp = cp;
}
public static void main(String[] args) throws InterruptedException {
ConsumerProducer cp = new ConsumerProducer();
WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp);
WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp);
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
t1.join();
t2.join();
}
@Override
public void run() {
while (true) {
if (threadType.equalsIgnoreCase("Consumer")) {
synchronized (cp) {
try {
/*
* Consumer will wait when there is nothing to get and he will release the lock of cp.
* So that producer has change to go into the synchronized block.
*/
if (null == cp.get()) {
cp.wait();
}
consume();
System.out.println("notify from Consumer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
synchronized (cp) {
try {
/*
* Producer only produce when there is nothing or he will wait. At the same time, he will release the lock of cp.
* So that consumer has chance to go into the synchronized block.
*/
if (null != cp.get()) {
cp.wait();
}
i++;
produce();
System.out.println("notify from Producer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (i == 5) {
break;
}
}
}
public void consume() {
System.out.println("getting: " + cp.get());
cp.clearString();
}
public void produce() {
System.out.println("Putting: Counter" + i);
cp.put("Counter" + i);
}}
另见 ConsumerProducer class。
public class ConsumerProducer {
public String stringPool = null;
public void put(String s){
stringPool = s;
}
public String get(){
return stringPool;
}
public void clearString(){
stringPool = null;
}
}
更新代码在这里:
ConsumerProducer.java:
public class 消费者生产者 {
public volatile String stringPool = null;
public void put(String s){
this.stringPool = s;
}
public String get(){
String ret = this.stringPool;
//this.stringPool = null;
return ret;
}
//added
public void clearString(){
this.stringPool = null;
}
}
WaitNotifyTest.java
public class WaitNotifyTest 实现 Runnable {
private String threadType;
public ConsumerProducer cp;
public static volatile int i = 0;
public WaitNotifyTest(String threadType, ConsumerProducer cp) {
this.threadType = threadType;
this.cp = cp;
}
public static void main(String[] args) throws InterruptedException {
ConsumerProducer cp = new ConsumerProducer();
WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp);
WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp);
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
t1.join();
t2.join();
}
@Override
public void run() {
while (true) {
if (threadType.equalsIgnoreCase("Consumer")) {
synchronized (cp) {
try {
if (null == cp.get()) {
cp.wait();
}
consume();
System.out.println("notify from Consumer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
synchronized (cp) {
try {
if (null != cp.get()) {
cp.wait();
}
i++;
produce();
System.out.println("notify from Producer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (i == 5) {
break;
}
}
}
public void produce() {
System.out.println("Putting: Counter" + i);
cp.put("Counter" + i);
}
public void consume() {
System.out.println("getting: " + cp.get());
cp.clearString();
}
}
我有一个 ConsumerProducer 对象,我想从两个不同的线程获取它的锁。 class如下:
public class ConsumerProducer {
public String stringPool = null;
public void put(String s){
stringPool = s;
}
public String get(){
String ret = stringPool;
stringPool = null;
return ret;
}
}
线程实现class如下:
public class WaitNotifyTest implements Runnable {
private String threadType;
public ConsumerProducer cp;
public static volatile int i = 1;
public WaitNotifyTest(String threadType, ConsumerProducer cp) {
this.threadType = threadType;
this.cp = cp;
}
public static void main(String[] args) throws InterruptedException {
ConsumerProducer cp = new ConsumerProducer();
WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp);
WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp);
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
t1.join();
t2.join();
}
@Override
public void run() {
while (true) {
if (threadType.equalsIgnoreCase("Consumer")) {
synchronized (cp) {
try {
if (null != cp.get()) {
cp.wait();
}
consume();
System.out.println("notify from Consumer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
synchronized (cp) {
try {
if (null == cp.get()) {
cp.wait();
}
produce();
System.out.println("notify from Producer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (i == 5) {
break;
}
i++;
}
}
public void consume() {
System.out.println("Putting: Counter" + i);
cp.put("Counter" + i);
}
public void produce() {
System.out.println("getting: " + cp.get());
}
}
但是当我 运行 代码时它正面临某种死锁并且它像
一样被卡住打印Putting: Counter3
notify from Consumer
出现了严重错误,但我无法确定。请帮忙。
您的消费者正在做生产者的工作,而生产者正在做消费者的工作。 交换他们的责任并修改条件等待。请参考下面的代码。
- 消费者会等到什么都拿不到的时候,他就会释放cp的锁。这样生产者就有机会进入同步块。
- 生产者只有在什么都没有的时候才生产,否则他会等待。之后,他就会释放cp的锁。这样消费者就有机会进入同步块。
- 消费者是拿东西的人。
- Producer 是谁把东西放到 table。
- 根据您的评论。你想把计数器从 1 到 5,所以你应该只在生产者线程中添加 i++。如何控制它在两个线程中的增加?
从
cp
对象中调用get()
不判断是消费者还是生产者,而是将null赋给stringPool
。这显然是错误的,并且会使消费者从 public space 中获取 null。我添加了一个新方法clearString()
,只有当消费者消费了产品时,它才会将 public space 设置为 null。public class WaitNotifyTest implements Runnable { private String threadType; public ConsumerProducer cp; public static volatile int i = 0; public WaitNotifyTest(String threadType, ConsumerProducer cp) { this.threadType = threadType; this.cp = cp; } public static void main(String[] args) throws InterruptedException { ConsumerProducer cp = new ConsumerProducer(); WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp); WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp); Thread t1 = new Thread(test1); Thread t2 = new Thread(test2); t1.start(); t2.start(); t1.join(); t2.join(); } @Override public void run() { while (true) { if (threadType.equalsIgnoreCase("Consumer")) { synchronized (cp) { try { /* * Consumer will wait when there is nothing to get and he will release the lock of cp. * So that producer has change to go into the synchronized block. */ if (null == cp.get()) { cp.wait(); } consume(); System.out.println("notify from Consumer"); cp.notify(); } catch (InterruptedException e) { e.printStackTrace(); } } } else { synchronized (cp) { try { /* * Producer only produce when there is nothing or he will wait. At the same time, he will release the lock of cp. * So that consumer has chance to go into the synchronized block. */ if (null != cp.get()) { cp.wait(); } i++; produce(); System.out.println("notify from Producer"); cp.notify(); } catch (InterruptedException e) { e.printStackTrace(); } } } if (i == 5) { break; } } } public void consume() { System.out.println("getting: " + cp.get()); cp.clearString(); } public void produce() { System.out.println("Putting: Counter" + i); cp.put("Counter" + i); }}
另见 ConsumerProducer class。
public class ConsumerProducer {
public String stringPool = null;
public void put(String s){
stringPool = s;
}
public String get(){
return stringPool;
}
public void clearString(){
stringPool = null;
}
}
更新代码在这里:
ConsumerProducer.java:
public class 消费者生产者 {
public volatile String stringPool = null;
public void put(String s){
this.stringPool = s;
}
public String get(){
String ret = this.stringPool;
//this.stringPool = null;
return ret;
}
//added
public void clearString(){
this.stringPool = null;
}
}
WaitNotifyTest.java public class WaitNotifyTest 实现 Runnable {
private String threadType;
public ConsumerProducer cp;
public static volatile int i = 0;
public WaitNotifyTest(String threadType, ConsumerProducer cp) {
this.threadType = threadType;
this.cp = cp;
}
public static void main(String[] args) throws InterruptedException {
ConsumerProducer cp = new ConsumerProducer();
WaitNotifyTest test1 = new WaitNotifyTest("Consumer", cp);
WaitNotifyTest test2 = new WaitNotifyTest("Producer", cp);
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
t1.join();
t2.join();
}
@Override
public void run() {
while (true) {
if (threadType.equalsIgnoreCase("Consumer")) {
synchronized (cp) {
try {
if (null == cp.get()) {
cp.wait();
}
consume();
System.out.println("notify from Consumer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
synchronized (cp) {
try {
if (null != cp.get()) {
cp.wait();
}
i++;
produce();
System.out.println("notify from Producer");
cp.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if (i == 5) {
break;
}
}
}
public void produce() {
System.out.println("Putting: Counter" + i);
cp.put("Counter" + i);
}
public void consume() {
System.out.println("getting: " + cp.get());
cp.clearString();
}
}