用于指示某些值的Java信号/事件机制可用
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了用于指示某些值的Java信号/事件机制可用,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4889字,纯文字阅读大概需要7分钟。
内容图文
![用于指示某些值的Java信号/事件机制可用](/upload/InfoBanner/zyjiaocheng/800/800d095bf98c45d29000daec9a921b1c.jpg)
我有一个拥有一个Thread的生成器类,其中确定要生成的许多“记录”,然后生成那么多记录(放在BlockingQueue中以供另一个线程检索).
我希望另一个线程知道将生成多少条记录(其中包括合理的进度报告).
似乎Future给了我正确的接口,但我是Java的新手,并不确定实现它的惯用方法.
我的背景是在C / Win32中,所以我通常使用win32“Event”(由CreateEvent创建(0,true,false,0),使用SetEvent和WaitForSingleObject进行信号和等待实现).我注意到Java有一个CountDownLatch,但是这种感觉比我想要的更重(有点类似于当我真的想要一个布尔值时使用int),而且对于这个目的来说似乎不直观(无论如何).
所以这是使用CountDownLatch和Future的代码.我在这里稍微提炼了我的实际代码(删除了不相关的实现细节并忽略了所有错误处理).
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public abstract class Generator {
private CountDownLatch numRecordsSignal = new CountDownLatch(1);
private int numRecords;
private BlockingQueue<Record> queue = new LinkedBlockingQueue<Record>();
public Generator() {
new Thread(new Runnable() {
@Override
public void run() {
numRecords = calculateNumRecords();
numRecordsSignal.countDown();
for (Record r : generateRecords()) {
try {
queue.put(r);
} catch (InterruptedException e) {
// [ ... snip ... ]
}
}
}
}).start();
}
public Future<Integer> numRecords() {
return new Future<Integer>() {
// Ignore cancel for now (It wouldn't make sense to cancel
// just this part of the Generator's work, anyway).
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public Integer get() throws InterruptedException {
numRecordsSignal.await();
return numRecords;
}
public Integer get(long timeout, TimeUnit unit)
throws InterruptedException {
numRecordsSignal.await(timeout, unit);
return numRecords;
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
// Since we can't cancel, just check the state of the
// signal
return numRecordsSignal.getCount() == 0;
}
};
}
public Record nextRecord() throws InterruptedException {
return queue.take();
}
/** --- Boring stuff below this line --- */
public interface Record { }
protected abstract int calculateNumRecords();
protected abstract Iterable<Record> generateRecords();
}
现在我的实际问题:
>对于单发信号,有没有比CountDownLatch更好的机制?
>我希望调用者能够等待或轮询结果,但不需要它们能够取消操作. Future是暴露这些东西的正确方法吗?
>这些东西看起来特别“非Java”吗?我完全走错了路吗?
编辑:
为了澄清,我希望调用者能够执行以下操作:
Generator gen = new Generator();
Integer numRecords = gen.numRecords().get(); // This call might block waiting for the result
numRecords = gen.numRecords().get(); // This call will never block, as the result is already available.
这只是我试图实现的一个缓慢的初始化值.一旦满足“初始化”条件,它应该锁定.一旦知道该值,就不会重新评估.
解决方法:
一边评论
You should not start a thread in a constructor – 可以想象,当线程启动时,Generator对象没有完全创建,例如,倒计时锁存器很可能为空.您可以在构造函数中创建线程,但应该以单独的方法启动它.您的呼叫代码将变为:
Generator g = new Generator();
g.start();
你的问题
你自己重新实现了未来,在我看来这不是必要的,也不是可取的.我将重新设计该类并使Generator实现Callable< Integer>并通过执行程序运行它.这为您提供了以下几点:
>从Generator中删除线程逻辑,这使您可以更高效地管理调用堆栈中更高级别的线程
>整数在您的调用代码中通过将来返回,您依靠JDK来处理实现
>我假设首先填充队列然后返回整数是可以的
>您可以根据需要多次调用future.get() – 它只会在第一次调用时阻塞.
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(1);
Future<Integer> future = executor.submit(new GeneratorImpl()); //a concrete implementation of Generator
int numRecords = 0;
try {
numRecords = future.get(); //you can use a get with timeout here
} catch (ExecutionException e) {
//an exception happened in Generator#call()
} catch (InterruptedException e) {
//handle it
}
//don't forget to call executor.shutdown() when you don't need it any longer
}
public abstract class Generator implements Callable<Integer> {
private BlockingQueue<Record> queue = new LinkedBlockingQueue<Record>();
@Override
public Integer call() {
int numRecords = calculateNumRecords();
for (Record r : generateRecords()) {
try {
queue.put(r);
} catch (InterruptedException e) {
// [ ... snip ... ]
}
}
return numRecords;
}
public Record nextRecord() throws InterruptedException {
return queue.take();
}
/**
* --- Boring stuff below this line ---
*/
public interface Record {
}
protected abstract int calculateNumRecords();
protected abstract Iterable<Record> generateRecords();
}
编辑
如果需要asap返回numRecods,可以在单独的线程中填充队列:
public Integer call() {
int numRecords = calculateNumRecords();
new Thread(new Runnable() {
@Override
public void run() {
for (Record r : generateRecords()) {
try {
queue.put(r);
} catch (InterruptedException e) {
// [ ... snip ... ]
}
}
}
}).start(); //returns immediately
return numRecords;
}
内容总结
以上是互联网集市为您收集整理的用于指示某些值的Java信号/事件机制可用全部内容,希望文章能够帮你解决用于指示某些值的Java信号/事件机制可用所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。