在我正在编写的一些代码中,有几个地方我可以这样做:
public MyThread extends Thread{
boolean finished = false;
BlockingQueue<Foo> blockingQueue new LinkedBlockingQueue<Foo>();
public void run(){
while(!finished || (finished && !blockingQueue.isEmpty())){
try{
Foo f = blockingQueue.take();
insertIntoDatabase(f);
}
catch(InterruptedException e){
}
}
}
public void insertThis(Foo f) throws InterruptedException{
blockingQueue.put(f);
}
public void stop(){
finished = true;
this.interrupt();
}
}然而,这会导致问题,因为线程在insertIntoDatabase()方法中时有时会中断。当我们使用Apache Derby时,它抛出了一个刺耳的声音(也就是:"java.sql.SQLException: Derby线程在磁盘I/O操作期间收到一个中断,请检查您的应用程序是否有中断的来源。“),所有后续的数据库通信都会陷入混乱。当线程不在阻塞队列中等待时,有没有什么好的方法来保护线程不受中断的影响,或者将中断定位在阻塞队列中?
我所看到或想到的两个解决方案是:将一个“毒丸”对象插入到队列中以关闭它,以及有一个可以由stop()方法检查的额外boolean interruptsWelcome字段,但这两个解决方案对我来说都不是特别有吸引力-我要么必须扰乱类层次结构(Foo不是一个微不足道的类),要么就必须生成大量的同步代码。有没有更整洁的东西?
发布于 2011-01-20 00:38:43
您可能想要做的第一件事是使用ExecutorService。其中您可以使用单个线程提交foo请求。
class FooRunner{
ExecutorService service = Executors.newSingleThreadExecutor();
//where RunnableFoo extends Foo and implements Runnable
public void insertThis(RunnableFoo f) throws InterruptedException{ Run
service.submit(f);
}
public void stop(){
service.shutdown();
}
}如果你愿意,你的runnable本身可以忽略中断的异常
class RunnableFoo extends Foo implements Runnable{
public void run(){
try{
insertIntoDatabase(this);
}catch(InterruptedException ex){
ex.printStackTrace();
}
}
}编辑:
我看到了你对另一个答案的评论,并从使用ExecutorService的角度回答了这个问题。通过使用singleThreadExeuctor,您可以通过线程限制将上传限制为一次。如果只有一个线程在服务中运行,那么一次只有一个runnable线程会运行。其他的只会排队,直到前一个完成。
发布于 2011-01-20 00:34:09
如果你想要的是在运行insertIntoDatabase()时不允许线程中断,那就去掉对这个方法的调用来分离Runnable,并将其提交给单独的Executor:
while(!finished || (finished && !blockingQueue.isEmpty())){
try{
final Foo f = blockingQueue.take();
executor.submit(new Runnable() {
public void run() {
insertIntoDatabase(f);
}
});
}
catch(InterruptedException e){
}
}发布于 2011-01-20 01:16:24
您可以放置前哨数值以停止处理。这不需要中断或复杂的检查。
public class MyThread extends Thread{
static final Foo STOP = new Foo();
final BlockingQueue<Foo> queue = new LinkedBlockingQueue<Foo>();
public void run(){
try{
Foo f = queue.take();
while(f != STOP) {
insertIntoDatabase(f);
f = queue.take();
}
} catch(InterruptedException e) {
e.printStackTrace();
}
}
public void insertThis(Foo f) {
queue.add(f); // never fills up.
}
public void stop() {
queue.add(STOP);
}
}另一种方法可能是使用ExecutorService。
public class DatabaseWriter {
final ExecutorService es = Executors.newSingleThreadExecutor();
public void insertThis(final Foo f) {
es.submit(new Runnable() {
public void run() {
insertIntoDatabase(f);
}
});
}
public void stop() {
es.shutdown();
}
}https://stackoverflow.com/questions/4737870
复制相似问题