[英]Conditional thread interrupt
在我正在處理的某些代碼中,有幾個地方我會做這樣的事情:
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
字段可以通過stop()
方法進行檢查,但是都不能對我來說特別有吸引力-我要么不得不弄亂類的層次結構( Foo
並不是一個簡單的類),要么產生大量的同步代碼。 有沒有更整潔的東西?
您可能要做的第一件事是使用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,您將只能通過線程約束限制一次上傳。 如果服務中僅運行一個線程,則一次只能運行一個可運行線程。 其他的只會排隊直到上一個完成。
如果您只想在運行insertIntoDatabase()
時不允許線程中斷,請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){
}
}
您可以放置哨兵值以停止處理。 這不需要中斷或復雜的檢查。
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();
}
}
然后不要使用this.interrupt()。 看來它按預期工作,但是JDBC驅動程序將InterruptedException轉換為SQLException,從而繞過了異常處理。
只需設置完成的布爾值,然后等待所有I / O完成即可。
讀取finished
變量應該足夠了,但前提是它是volatile
。 如果沒有volatile,則不能保證讀取線程會看到對其進行寫操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.