package thread;
public class ProducerConsumerTest {
public static void main(String[] args) {
Queue queue = new Queue();
Producer p = new Producer(queue);
Consumer c = new Consumer(queue);
p.start();
c.start();
}
}
class Queue {
private int data;
private boolean isFull = false;
public synchronized int get() {
if (!isFull) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isFull = false;
notify();
return data;
}
public synchronized void set(int data) {
if (!isFull) {
this.data = data;
// System.out.println("Producer put data "+data);位置1
isFull = true;
notify();
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Producer extends Thread {
Queue queue;
Producer(Queue queue) {
this.queue = queue;
}
public void run() {
for (int i = 1; i <= 10; i++) {
System.out.println("Producer put data " + i);//位置2。把这句代码从上面注释的地方挪到这个地方。
queue.set(i);
}
}
}
class Consumer extends Thread {
Queue queue;
Consumer(Queue queue) {
this.queue = queue;
}
public void run() {
while (true) {
synchronized (queue) {
System.out.println("get data " + queue.get());//3
}
}
}
}
//现在的问题是,把位置1的注释掉,使位置2生效后,同样线程同步。疑问是,应该存在这样的可能:在3只执行了queue.get()后,跳出,位置2获得执行,这样应该没有同步啊,也就是,put put 。
------解决方案--------------------------------------------------------
对这种问题我也很苦恼……
------解决方案--------------------------------------------------------
回帖拿分~~
------解决方案--------------------------------------------------------
我也要分 都给我
------解决方案--------------------------------------------------------
LZ想问什么,把1改到2,2没在同步块中,不能保证一致
简单的说,比如
synchronized(A) {
System.out.println("A");
}
System.out.println("B");
这两个打印不一定能保证一致,因为线程(姑且叫这个线程为线程1)执行完synchronized块后,刚要打印System.out.println("B");的时候,系统可能把CPU收回,分配给其他线程(线程2线程3线程4等等),其他线程可能也会打印别的东西,过了一段时间线程1又获得CPU权,继续打印System.out.println("B");这样,System.out.println("A");和System.out.println("B");就不能保证是连续的,也就是说从System.out.println("A");到System.out.println("B");不一致,因为中间其他线程可能作了某些操作让结果发生变化了。
------解决方案--------------------------------------------------------
不知道LZ想要问什么问题,但是同意5楼观点,位置1和2我都没注释,另外我把程序加了句话
class Queue {
private int data;
private boolean isFull = false;
public synchronized int get() {
if (!isFull) {
try {
System.out.println("有吗");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
得到结果是:
Producer put data0
Producer put data0
get data0
有吗?
Producer put data1
Producer put data1
get data1
有吗?
为什么在执行完get data()后它又去执行get data()里面的if语句块了?哪位大虾能否解释一下?谢谢!
------解决方案--------------------------------------------------------
还是不太明白你说的,首先在3只执行了queue.get()后,锁还是被c线程占用着,因为c的run是synchronized(queue),所以必须是执行完整个System.out.println结束退出synchronized块以后,p才有可能获得锁权利而执行
可以假设一下你的程序执行
情况1 p先执行,打印2,假如p的cpu没被收回,那么p继续执行queue.set,会打印1,于是就会 put put,然后p发生wait,然后c执行会打印3(上面说了只有打印3结束c才会释放锁),**然后系统随机分配cpu给p或c,我们分a,b两种可能讨论
a)这时如果cpu分配给c,那么c会发生进入get的if (!isFull)发生wait,然后p执行,打印2,而c此时还在wait,所以p继续执行,打印1,于是有put put,然后唤醒c,p发生wait,然后c执行,会打印3;
b)如果这时cpu分配给p,那么p会打印2,这时我们分1)和2)两种可能讨论
1)p的cpu被收回分配给c,然后c执行get,进入if (!isFull)发生wait,然后p执行,打印1,于是发生put put,然后唤醒c,p发生wait,然后c执行,会打印3