我正在运行两个线程类和一个第三个类(执行)它们。
Class1 extends Thread{
public void run(){
while(!Thread.currentThread().isInterrupted()){
Thread.sleep(random());
//random will ensure non-periodicity in generating strings
//Because of this, sometimes, many strings are generated simultaneously and other times, there is delay.
Execute.q.add(generateRandomString());
}
}
}
Class2 extends Thread{
public void run(){
while(!Thread.currentThread().isInterrupted()){
Thread.yield();
if(!Execute.q.isEmpty){
System.out.println(Execute.q.remove());
}
}
}
}
public class Execute{
public static Queue<String> q = new LinkedList<String>();
public static void main(String args[]){
(new Class1()).start();
(new Class1()).start();
(new Class2()).start();
(new Class2()).start();
}
}
我面临的问题是这些:
一些生成的字符串被打印了不止一次,这意味着一旦有一些字符串被推入
q
,多个线程会同时删除该元素并打印。某些生成的字符串永远不会打印。
有时,输出会延迟,即如果 Class1 生成 5 个字符串,则只打印 3 个字符串。现在,如果它再生成 3 个字符串,则打印前 2 个(左)字符串。
我该如何解决这些问题?
要么使用线程安全的Queue
从java.util.concurrent
实现(例如 BlockingQueue
) 或使用synchronized
关键字。
另请参阅 https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
LinkedList
不是线程安全的。你应该使用某种BlockingQueue
:
public static BlockingQueue<String> q = new ArrayBlockingQueue<String>(20);
一些生成的字符串被打印了不止一次,这意味着一旦有一些字符串被推入 q,多个线程就会同时删除该元素并打印。
这很可能是由于对q
的访问未同步,即Class2
调用的两个或多个实例几乎同时remove()
弄乱了也不安全的LinkedList
实现。
您可能想要的是循环内的synchronized(Execute.q){ ... }
块(不包括睡眠和收益调用)。
某些生成的字符串永远不会打印。
这可能与上述原因相同,因为您在同时呼叫remove()
等时会弄乱LinkedList
。
有时,输出会延迟,即如果 Class1 生成 5 个字符串,则只打印 3 个字符串。现在,如果它再生成 3 个字符串,则打印前 2 个(左)字符串。
线程不保证以任何顺序运行,因此生产者可以运行 5 次,然后选择使用者运行 3 次。这里没有什么不寻常的。
尝试使用 public static volatile Queue<String> q = new LinkedList<String>();
而不是 public static Queue<String> q = new LinkedList<String>();
它应该在不同步方法或使用同步块的情况下有所帮助。