我有一个简单的调用线程,它做了简单的工作。当条件满足时
我想调用或通知基类(启动线程的那个)
工作完成了。
做这个的最好方式是什么 ?
class TaskThread implements Runnable
{
private int result = -1;
public TaskThread()
{
}
//must be thread safe
public synchronized int getResult()
{
return result;
}
@Override
public void run() {
if(result==-1 || result < 0)
{
StartFoo();
result = InvokeAPI();
if(result == 1)
{
// HERE i like to do something to notify the outside world that the job is done ...
}
}
}
}
//Base class
public class ScheduledThreadsManager {
private static ScheduledThreadsManager instance = null;
private ScheduledExecutorService scheduler;
private Runnable pTaskThread = null ;
protected ScheduledThreadsManager()
{
}
//must be set only once in the app life cycle
public void Init(int corePoolSize,
long TimeUnitINSeconds)
{
pTaskThread = new TaskThread();
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(pTaskThread,1,TimeUnitINSeconds,TimeUnit.SECONDS);
}
public int getResult()
{
return pTaskThread.;
}
// Runtime initialization
// By defualt ThreadSafe
public static ScheduledThreadsManager getInstance() {
if(instance == null){
synchronized (ScheduledThreadsManager.class) {
if(instance == null){
instance = new ScheduledThreadsManager();
}
}
}
return instance;
}
public void ShutdownNow()
{
pTaskThread = null ;
scheduler.shutdown();
}
}
现在这就是我所说的:
//somewhere in the code
ScheduledThreadsManager.getInstance().init(1,10);
int runThis = true;
while(runThis)
{
int ifOne = ScheduledThreadsManager.getInstance().getResult()
if(ifOne==1)
{
runThis = false;
ScheduledThreadsManager.getInstance().ShutdownNow()
}
}
我不确定是最好的方法,我能以某种方式从TaskThread运行方法并更新ScheduledThreadsManager吗?
答案 0 :(得分:3)
我认为最好的方法是给任务一个回调函数:
<%= form_for :trip, url: {action: "index"}, html: {method: "get"} do |f| %>
<%= f.select :country_obj_id, options_for_select(@countries.collect { |country|
[country.name.titleize, country.id] }, @countries.first.name), {}, { id: 'countries_select', class: "form-control" } %>
<%= f.select :city_obj_id, options_for_select(@cities.collect { |city|
[city.name.titleize, city.id] }, 0), {}, { id: 'cities_select', class: "form-control" } %>
<%= f.submit "Go!" %>
<% end %>
然后在您的任务中,最后添加Runnable callback = () -> System.out.println("done!");
。或者,如果您的任务返回了您需要使用的值,请使用callback.run();
代替Consumer
。
这是一个有效的例子:
Runnable
这允许您例如调用public class Task implements Runnable {
private final Consumer<String> callback;
public Task(Consumer<String> callback) {
this.callback = callback;
}
@Override
public void run() {
// do actual work here instead
String result = new Random().nextInt(2) == 0 ? "a" : "b";
// call a private method in Caller
callback.accept(result);
}
}
public class Caller {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit(new Task((result) -> print(1, result)));
executorService.submit(new Task((result) -> print(2, result)));
executorService.submit(new Task((result) -> print(3, result)));
Thread.sleep(2000);
}
private static void print(int id, String result) {
System.out.println("task " + id + " done, returned: " + result);
}
}
的私有方法,您的Caller
将对此一无所知。
答案 1 :(得分:3)
不要通知调用对象:使用ExecutorService
和Future
。
您可以向Runnable
提交ExecutorService
并返回Future
:
Future<?> future = executorService.submit(myRunnable);
现在你可以调用future.get()
(可选择暂停),这将阻止直到Future完成:
future.get();
future.get(5, TimeUnit.MINUTES);
这意味着您不需要引入任何新的回调接口或类似接口。您也无需立即致电future.get()
:您可以提交一大堆任务,然后再致电get
。
请注意,如果您向Callable<T>
提交ExecutorService
,则会返回Future<T>
:如果您希望长时间运行的计算返回值,这将非常有用。
Guava使用ListenableFuture
扩展Future
接口,允许您在Future
完成后执行回调。 Java 8还增加了CompleteableFuture
,但我还处于黑暗时代,所以我从未使用过它:)
答案 2 :(得分:1)
你可以通过一个界面来实现它,例如
interface SomethingToBeCalled{
void notfiy();
}
你的BaseClass扩展了这个
ScheduledThreadsManager implements SomethingToBeCalled{
void notify() {...};
}
你给你的Task Constructor这个接口
public TaskThread(SomethingToBeCalled smth)
{
this.smth = smth;
}
现在您可以通知BaseClass
if(result == 1)
{
smth.notify();
}