在我正在研究的一些代码中,有几个地方我会做这样的事情:
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操作期间收到一个中断,请检查您的应用程序是否有中断源。”) ,以及随后的所有数据库通信都陷入了困境。当没有等待阻塞队列,或者在阻塞队列中定位中断时,是否有任何保护线程免受中断的整洁方法?
我见过的两个解决方案建议或已经发生在我的队列中插入一个“毒丸”对象来关闭它,并有一个额外的boolean interruptsWelcome
字段,可由{ {1}}方法,但对我来说都不是特别有吸引力 - 我要么必须弄乱类层次结构(stop()
不是一个普通的类)或者产生大量的同步代码。有什么更整洁的东西吗?
答案 0 :(得分:3)
您可能想要做的第一件事是使用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。其他人将排队等到上一次结束。
答案 1 :(得分:2)
如果你想要的只是在运行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){
}
}
答案 2 :(得分:2)
您可以放置sentinel值以停止处理。这不需要中断或复杂的检查。
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();
}
}
答案 3 :(得分:0)
不要使用this.interrupt()。它似乎按预期工作,但JDBC驱动程序正在将InterruptedException转换为SQLException,从而绕过了异常处理。
只需设置完成的布尔值并等待所有I / O完成。
答案 4 :(得分:0)
阅读finished
变量应该足够了,但前提是volatile
。没有volatile,就不能保证读取线程会看到它的写入。