Java 如何从工作队列任务中获得结果?

Java 如何从工作队列任务中获得结果?,java,multithreading,java-8,Java,Multithreading,Java 8,我实现了一个简单的工作队列,它接收来自多个不同线程的任务。我希望这些任务向其源线程返回一个值,但不知道如何执行。 我考虑过使用未来,但是没有办法显式地设置未来的值。我可以使用一个属性,但我不相信它们是线程安全的 每个任务都是DBRequest的一个实现。实际内容各不相同,但所有活动的结果都是字符串。 异步线程创建DBRequest并将其提交到队列。队列运行任务,任务生成一个字符串。如何将该字符串返回到创建DBRequest的线程,以及如何使创建者线程等待结果 public interface D

我实现了一个简单的工作队列,它接收来自多个不同线程的任务。我希望这些任务向其源线程返回一个值,但不知道如何执行。 我考虑过使用未来,但是没有办法显式地设置未来的值。我可以使用一个属性,但我不相信它们是线程安全的

每个任务都是DBRequest的一个实现。实际内容各不相同,但所有活动的结果都是字符串。 异步线程创建DBRequest并将其提交到队列。队列运行任务,任务生成一个字符串。如何将该字符串返回到创建DBRequest的线程,以及如何使创建者线程等待结果

public interface DBRequest {
    String execute(VdtsSysDB vdtsSysDB, BoardLoad currentLoad);
}

public class DBQueue implements Runnable {
    private static DBQueue dbQueue;
    private LinkedBlockingQueue<DBRequest> queue = new LinkedBlockingQueue<>();
    private VdtsSysDB vdtsSysDB = new VdtsSysDB();
    private ReentrantLock lock = new ReentrantLock();
    private static final Logger LOG = LoggerFactory.getLogger(DBQueue.class);
    private boolean kill = false;

    private BoardLoad currentLoad;
    private ProgressController progressController;

    public static DBQueue getInstance() {
        if (dbQueue == null) synchronized (DBQueue.class) {
            if (dbQueue == null)
                dbQueue = new DBQueue();
        }
        return dbQueue;
    }

    private DBQueue() {
    }

    public ReentrantLock getLock() {
        return lock;
    }

    @Override
    public void run() {
        LOG.info("Starting DBQueue loop. Kill {}.", kill);
        while (!kill) {
            DBRequest dbRequest = removeRequest();
            if (dbRequest != null) {
                lock.lock();
                String result = dbRequest.execute(vdtsSysDB, currentLoad);
                lock.unlock();
                if (progressController != null) Platform.runLater(() ->
                        progressController.updateDisplay(currentLoad));
            }
        }
        vdtsSysDB.getEntityManager().close();
    }


    public void addRequest(DBRequest dbRequest) {
        try {
            queue.add(dbRequest);
            LOG.info("Added request.");
        } catch (Exception e) {
            LOG.error("Can't add element.", e);
        }
    }

    private DBRequest removeRequest() {
        DBRequest result = null;
        try {
            //result = queue.poll(10, TimeUnit.SECONDS);
            result = queue.take();
        } catch (Exception e) {
            LOG.error("Exception.", e);
        }
        return result;
    }

    public void killDBQueue() {
        kill = true;
        LOG.info("Shutting down DBQueue.");
    }

    public static void start() {
        Thread thread = new Thread(DBQueue.getInstance(), "DBQueue Thread");
        thread.start();
        LOG.info("Starting DBQueue.");
    }

    public BoardLoad getCurrentLoad() {
        if (currentLoad == null)
            currentLoad = BoardLoad.getLastOpenLoad(vdtsSysDB);
        return currentLoad;
    }

    public void setCurrentLoad(BoardLoad proposedLoad) {
        // We can only have one open load, and by definition, the current load is open. So close it.
        if (this.currentLoad != null && !this.currentLoad.equals(proposedLoad)) {
            currentLoad.close(vdtsSysDB);
            if (proposedLoad != null) {
                this.currentLoad = vdtsSysDB.getEntityManager().find(BoardLoad.class, proposedLoad.getId());
            } else this.currentLoad = null;
        }
    }

    public ProgressController getProgressController() {
        return progressController;
    }

    public void setProgressController(ProgressController progressController) {
        this.progressController = progressController;
    }
}
公共接口DBRequest{
字符串执行(VdtsSysDB VdtsSysDB,BoardLoad currentLoad);
}
公共类DBQueue实现可运行{
私有静态数据库队列;
私有LinkedBlockingQueue=新LinkedBlockingQueue();
私有VdtsSysDB VdtsSysDB=新VdtsSysDB();
private ReentrantLock lock=new ReentrantLock();
私有静态最终记录器LOG=LoggerFactory.getLogger(DBQueue.class);
私有布尔kill=false;
专用板负载电流负载;
私有进程控制器进程控制器;
公共静态DBQueue getInstance(){
如果(dbQueue==null)已同步(dbQueue.class){
if(dbQueue==null)
dbQueue=新的dbQueue();
}
返回dbQueue;
}
私有数据库队列(){
}
公共ReentrantLock getLock(){
返回锁;
}
@凌驾
公开募捐{
LOG.info(“启动DBQueue循环.Kill{}.”,Kill);
而(!杀死){
DBRequest DBRequest=removeRequest();
if(dbRequest!=null){
lock.lock();
String result=dbRequest.execute(vdtsSysDB,currentLoad);
lock.unlock();
if(progressController!=null)Platform.runLater(()->
progressController.updateDisplay(currentLoad));
}
}
vdtsSysDB.getEntityManager().close();
}
公共void addRequest(DBRequest DBRequest){
试一试{
添加(dbRequest);
LOG.info(“添加请求”);
}捕获(例外e){
LOG.error(“无法添加元素。”,e);
}
}
私有DBRequest removeRequest(){
DBRequest result=null;
试一试{
//结果=queue.poll(10,时间单位:秒);
结果=queue.take();
}捕获(例外e){
日志错误(“异常”,e);
}
返回结果;
}
public void killDBQueue(){
kill=true;
LOG.info(“正在关闭DBQueue”);
}
公共静态void start(){
线程线程=新线程(DBQueue.getInstance(),“DBQueue线程”);
thread.start();
LOG.info(“启动DBQueue”);
}
公共BoardLoad getCurrentLoad(){
if(currentLoad==null)
currentLoad=BoardLoad.getLastOpenLoad(vdtsSysDB);
回流负载;
}
公共无效setCurrentLoad(BoardLoad proposedLoad){
//我们只能有一个打开的负载,根据定义,当前负载是打开的。所以关闭它。
如果(this.currentLoad!=null&&!this.currentLoad.equals(proposedLoad)){
电流负载关闭(vdtsSysDB);
如果(proposedLoad!=null){
this.currentLoad=vdtsSysDB.getEntityManager().find(BoardLoad.class,proposedLoad.getId());
}否则,this.currentLoad=null;
}
}
公共ProgressController getProgressController(){
返回控制器;
}
公共无效setProgressController(ProgressController ProgressController){
this.progressController=progressController;
}
}
编辑:我使用这个队列来同步数据库访问,减少对锁的需要,并确保请求按顺序完成。我不相信有任何其他方法可以实现这种异步请求->同步请求更改。
但是我希望改变这种想法。

您应该在
DBRequest
接口中添加对提交线程的引用,并实现
setResult(String result)
(或类似)方法来接收结果。 您可以在提交线程
run()
方法上实现
CountDownLatch
等待(或类似方法),以便在
setResult
方法中将请求发送到队列时等待设置闩锁。
如果我不清楚,请告诉我,我会详细说明。

CompletableFuture
提供了一种设置未来值的方法。您可能希望通过运行此操作。您的代码中存在不少同步问题。您的队列听起来像
ExecutorService
而不是队列。您可以将任务提交到
ExecutorService
,后者返回
Future
返回。因此,提交要执行的任务的线程可以调用
Future.get()
以等待结果。@teppic可能会作为主题外的内容关闭。@200\u成功。啊。我道歉。我不知道协议。@MyStackRunnethOver感谢您修复代码部分。我还在学习。