我在ExecutorCompletionService中遇到了奇怪的行为。该项将被添加到ExecutorCompletionService.submit()中。然后它被处理并由之前提交的Callable工作线程返回。返回后,ExecutorCompletionService.take()永远不会看到它,所以永远不会看到阻止返回任何项目?我真的不确定发生了什么。我已经创建了打印行,可以看到它完成了Callable工作线程。一旦发生这种情况,ExecutorCompletionService.take应该准备好了,但在某些情况下,事情会被锁定,有时会很好吗?
我已经创建了一个测试用例,如果你运行它几次就会看到它会在某些情况下锁定并且从不接受任何已完成的线程
ThreadDeadlockDemo
import java.util.Observable;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
public class ThreadDeadlockDemo extends Observable implements Runnable {
private CompletionService<String> pool;
private ExecutorService executor ;
private Thread responseWorkerThread;
private HttpSchedulerWorker schedulerWorker;
private boolean shouldRun = true;
private int numThreadsInPool;
private BlockingQueue<String> queue;
public ThreadDeadlockDemo(int numThreads)
{
numThreadsInPool = numThreads;
executor = Executors.newFixedThreadPool(numThreads);
pool = new ExecutorCompletionService<String>(executor);
schedulerWorker = new HttpSchedulerWorker();
responseWorkerThread = new Thread(schedulerWorker);
responseWorkerThread.start();
queue = new LinkedBlockingQueue<String>();
new Thread(this).start();
}
public ThreadDeadlockDemo()
{
numThreadsInPool = 1;
executor = Executors.newFixedThreadPool(1);
pool = new ExecutorCompletionService<String>(executor);
schedulerWorker = new HttpSchedulerWorker();
responseWorkerThread = new Thread(schedulerWorker);
responseWorkerThread.start();
queue = new LinkedBlockingQueue<String>();
new Thread(this).start();
}
public void setThreadCount(int numThreads)
{
executor = Executors.newFixedThreadPool(numThreads);
pool = new ExecutorCompletionService<String>(executor);
numThreadsInPool = numThreads;
}
public void add(String info) {
queue.add(info);
}
@Override
public void run() {
// TODO Auto-generated method stub
while(shouldRun)
{
try {
String info = queue.take();
Callable<String> worker = new WorkerThread(info);
System.out.println("submitting to pooler: " + info);
pool.submit(worker);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* Inner class of proxy is a worker thread blocks until the pool has transactions complete as soon as they
* are complete it will send them to server for completion.
* @author Steve
*
*/
class HttpSchedulerWorker implements Runnable{
public void run() {
// TODO Auto-generated method stub
while(true)
{
String vulnInfo = null;
try {
Future<String> tmp = pool.take();
// Future<VulnInfo> tmp = pool.poll();
if(tmp != null)
vulnInfo = tmp.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(vulnInfo != null)
{
System.out.println("info was taken from pool completed: " + vulnInfo);
}
}
}
}
}
WorkerClass:这是添加到执行程序池并返回的线程工作者,但在某些情况下永远不会在ThreadlockDemos ExecutorCompletionService池中得到通知?
import java.util.concurrent.Callable;
public class WorkerThread implements Callable<String>{
String info;
WorkerThread(String info)
{
this.info = info;
}
//@Override
public String call() throws Exception {
System.out.println("sending vuln info: " + info);
return info;
}
}
这是我的测试类只是将项添加到队列中。这是从我的控制台打印出一个看起来失败的打印机。它添加到队列中的工作并返回值。但是take()从来没有被称为任何想法为什么?它有时会起作用,有时候会让我很难看到出现了什么问题。我很想在java中说出它的错误但我环顾四周并没有看到这些类有什么问题吗?
public class HttpSchedulerThreadedUnitTest {
ThreadDeadlockDemo scheduler;
public HttpSchedulerThreadedUnitTest(){
setupScheduler();
for(int i=0; i < 5;i++)
{
scheduler.add(i+"");
}
}
private void setupScheduler()
{
scheduler = new ThreadDeadlockDemo();
scheduler.setThreadCount(1);
}
public static void main(String[] args)
{
new HttpSchedulerThreadedUnitTest();
}
}
控制台打印:这是在WorkerThread完成时从不从池中运行的 提交给pooler:0 提交给pooler:1 提交给pooler:2 发送信息:0 提交给pooler:3 发送信息:1 提交给pooler:4 发送信息:2 发送信息:3 发送信息:4
控制台打印:它实际上正在从池返回中获取itenms! 提交给pooler:0 提交给pooler:1 提交给pooler:2 提交给pooler:3 提交给pooler:4 发送信息:0 信息取自游泳池完成:0 发送信息:1 信息取自游泳池完成:1 发送信息:2 信息取自游泳池完成:2 发送信息:3 信息取自游泳池完成:3 发送信息:4 信息来自完成的游泳池:4
答案 0 :(得分:0)
这是很多代码。如果你可以减少它(通过删除http相关的部分等)将是很好的。我也不确定After that return the ExecutorCompletionService.take never sees it so never sees the blocking to return anymore items?
您可以在锁定时进行线程转储,并查看哪个线程在代码的哪个位置被锁定。
与此同时,我确实看到一些看起来不对的代码。
while(requestQueue.isEmpty()){
try {
synchronized(this)
{
wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
在这里,您正在同步一个可运行的对象。这几乎总是错误的,因为runnable对象通常不会被多个线程访问。您还要测试synchronized语句之外的条件。通常你使用等待如下:
synchronized(lock){
while(!condition){
wait();
}
}
但是,我没有看到任何在runnable上调用notify的代码。这可能会导致程序挂起。基本上你在等待什么,但是没有人把你叫醒,所以你无限期地等待。这是否是您遇到的问题的原因,可以通过在发生这种情况时查看线程转储来轻松确定。
如果您正在使用队列,那么最好的建议是使用阻塞队列来处理请求队列。这样你就不必完全等待/通知业务了。