这是Java中的生产者-消费者场景。制作人在ArrayList中写作,而消费者则从中阅读。两者都在添加或删除元素之前锁定ArrayList对象。
你能帮我弄明白为什么它会引起恶作剧吗?
如果我在System.out.println(…)之后放置remove调用,它工作得很好(无限生产者和消费者都工作)。
buffer.remove(buffer.size()-1);
System.out.println("Consumed" + " " + buffer.get(buffer.size() - 1) + " size " + buffer.size());
完整代码:
public class Test {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>(10);
Producer producer = new Producer(arrayList);
Consumer consumer = new Consumer(arrayList);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(producer);
executorService.submit(consumer);
}
}
class Producer implements Runnable{
private final ArrayList<Integer> buffer;
public Producer(ArrayList<Integer> arrayList){
this.buffer = arrayList;
}
public void run(){
while (true) {
synchronized (buffer) {
while (isFull(buffer)) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer.add(1);
System.out.println("Produced" + " " + buffer.get(buffer.size() - 1) + " size " + buffer.size());
buffer.notifyAll();
}
}
}
private boolean isFull(ArrayList<Integer> buffer) {
return buffer.size() == 10;
}
}
class Consumer implements Runnable{
private final ArrayList<Integer> buffer;
public Consumer(ArrayList<Integer> buffer) {
this.buffer = buffer;
}
public void run(){
while (true) {
synchronized (buffer) {
while (isEmpty(buffer)) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer.remove(buffer.size()-1);
System.out.println("Consumed" + " " + buffer.get(buffer.size() - 1) + " size " + buffer.size());
buffer.notifyAll();
}
}
}
private boolean isEmpty(ArrayList<Integer> buffer) {
return buffer.size() == 0;
}
}
典型的输出在死锁的情况下,生产者释放锁后消费线程不会开始处理。
Produced 1 size 1
Produced 1 size 2
Produced 1 size 3
Produced 1 size 4
Produced 1 size 5
Produced 1 size 6
Produced 1 size 7
Produced 1 size 8
Produced 1 size 9
Produced 1 size 10
Consumed 1 size 9
Consumed 1 size 8
Consumed 1 size 7
Consumed 1 size 6
Consumed 1 size 5
Consumed 1 size 4
Consumed 1 size 3
Consumed 1 size 2
Consumed 1 size 1
Produced 1 size 1
Produced 1 size 2
Produced 1 size 3
Produced 1 size 4
Produced 1 size 5
Produced 1 size 6
Produced 1 size 7
Produced 1 size 8
Produced 1 size 9
Produced 1 size 10
JDK:jdk1.8.0_111型
下面是生产者和消费者线程的线程转储
"pool-1-thread-2" #11 prio=5 os_prio=31 tid=0x00007fb1e8039800 nid=0x3c03 waiting on condition [0x000070000fa72000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007aac942a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
"pool-1-thread-1" #10 prio=5 os_prio=31 tid=0x00007fb1e704d800 nid=0x3b03 in Object.wait() [0x000070000f96f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007aac8a998> (a java.util.ArrayList)
at java.lang.Object.wait(Object.java:502)
at com.vipin.threading.Producer.run(Test.java:36)
- locked <0x00000007aac8a998> (a java.util.ArrayList)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)