我正在尝试设计一个使用Executors.newSingleThreadExecutor()
制作的工作线程的Android应用程序但是我只希望该工作线程处理主线程发送的连续任务,同时保存属于该工作线程的一些信息。 (主线程不需要知道,只有工作线程应该在内部保留该信息。
// State saver class , once made by main thread only accessed by worker thread
public class StateSaver{
public int count;
}
// Runnable obj that will be sent to worker thread from main thread
public class rnbl implements Runnable{
final public StateSaver sv;
public rnbl(StateSaver sv){
this.sv = sv;
}
@Override
public void run(){
sv.count++;
}
}
// Main Thread
ExecutorService ex = Executors.newSingleThreadExecutor();
StateSaver sv = new StateSaver();
public void functionCalledByMainThread(){
ex.submit(new rnbl(sv));
}
然而问题是我发现当newSingleThreadExecutor长时间处于空闲状态时,它可能只是破坏它所做的线程并在需要时用新的线程替换它。
所以我担心的是,如果出现以下情况怎么办? :
工作线程更新了状态变量
变量在线程缓存内存中更新但尚未应用于主内存(变量不应该是易失性的)
工作线程被破坏
更新永远不会应用于主内存......
然后,如果执行程序创建一个新线程继续执行该任务,那么保存的状态可能不正确吗?当然使用volatile应该很容易,但我不需要使用volatile
或者是否可以保证当一个线程被销毁时,对变量所做的所有更改都会被刷新到主内存中?
答案 0 :(得分:1)
如果要确保当后终止的线程所做的更改对另一个线程可见,则可以使用Thread.join()
。这样可以保证发生在之前的关系。
例如:
Thread t = new Thread(new SomeRunnable());
t.start();
// do stuff
t.join();
// After the 'join', all memory writes made by Thread t are
// guaranteed to be visible to the current thread.
但实际上你问的是ExecutorService
线程无法用于“加入”。
以下内存一致性保证适用于ExecutorService
:
在向
Runnable
提交Callable
或ExecutorService
任务之前,线程中的操作发生在该任务采取的任何操作之前,反过来发生 - 之前通过Future.get()
检索结果。
因此,获得所需一致性的方法是在get()
上为任务调用Future
。
答案 1 :(得分:1)
ExecutorService只能在' run()'之后删除线程。方法完成了。只需实现线程生命周期的自定义协议(等待和处理消息中的实时forewer或者为特殊消息刷新状态和死亡):
class App {
static final String KILLER_MSG = "KILLER";
public static void main(String[] args) {
BlockingQueue<String> tasks = new ArrayBlockingQueue<String>(256);
ExecutorService pool = Executors.newCachedThreadPool();
// master / task producer
pool.submit(() -> {
tasks.add("task-0");
tasks.add("task-1");
tasks.add("task-2");
tasks.add(KILLER_MSG);
});
// slave / task consumer / worker
pool.submit(() -> {
while (true) {
String task = tasks.take();
if (KILLER_MSG.equals(task)) {
// flush state here
break; // and die
} else {
// process 'task' here
System.out.println("TASK: " + task);
}
}
});
}
}