執行緒阻塞和中斷(sleep、wait、io、鎖)四種恢復方式
阿新 • • 發佈:2019-02-01
1、執行緒阻塞
一個執行緒進入阻塞狀態可能的原因:
①通過呼叫sleep(millseconds)使任務進入休眠狀態;
class Demo1 implements Runnable throws InterruptedException{
public void run(){
Thread.sleep(1000);
}
}
②通過呼叫wait()使執行緒掛起,直到執行緒獲取notify()/notifyAll()訊息,(或者在Java SE5中java.util.concurrent類庫中等價的signal()/signalAll()訊息),執行緒才會進入就緒狀態;
class Demo2 implements Runnable{
public void run(){
Thread.await();
Thread.notify();
}
}
③任務在等待某個輸入 / 輸出流的完成;
class Demo3 implements Runnable throws InterruptedException{
private InputStream in;
public void run(){
in.read();
}
}
④任務試圖在某個物件上呼叫其同步控制方法,但是物件鎖不可用,因為另一個任務已經獲取了該鎖;
class Demo4 implements Runnable{
public synchronized void method1(){ }
public synchronized void method2(){ }
public void run(){
method1();
}
}
2、執行緒中斷的方法
Thread類包含interrupt()方法,用於終止阻塞任務;
1)中斷①②類執行緒休眠,掛起阻塞的方法
1.直接使用Thread.interrupt();
main(){
Thread t = new Thread(new Demo1());
t.interrupt();
}
2.使用Executor執行緒池,中斷執行緒池中的所有執行緒;
main(){
ExecutorService exec = Executors.newCachedThreadPool();
for(int i=0;i<5;i++)
exec.execute(new Demo1())
exec.shutdownNow();
}
3.使用Executor執行緒池,中斷執行緒池中單個阻塞的執行緒;
main(){
ExecutorService exec = Executors.newCachedThreadPool();
Futrue<?> f = exec.submit(new Demo1());
f.interrupt();
}
//中斷後的清除程式碼放置在InterruptedException異常的catch捕獲的程式碼塊中
2)中斷③類I/O阻塞的方法
使用Thread.iterrupt方法無法中斷I/O阻塞,這對於基於Web的程式是很不利的;
①有一種解決方法:關閉任務在其上發生阻塞的底層資源;
main(){
ExecutorService exec = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(8080);
InputStream socketInput = new Socket("localhost",8080)
exec.execute(socketInput);
exec.execute(Sytsem.in);
//exec.shutdownNow(); 無法中斷2個執行緒;
socketInput.close();
in.close();
exec.shutdownNow();
}
②java.nio類庫提供了更加人性化的I/O中斷,被阻塞的nio通道會自動地響應中斷;
class Demo impelenets Runnable{
private final SocketChannel sc;
public Demo(SocketChannel sc){ this.sc = sc;}
public void run(){
try{
sc.read(ByteBuffer.allocate(1));
}catch(CloseByInteruptedException e1){
}catch(AsyncronousCloseException e2){
}catch(IOException e3){
}
}
}
public Test {
public static void main(){
ExecutorService exec = Executors.newCachedThreadPool();
ServerSocket server = new ServerSocket(8080);
InetSocketAddress isa = new InetSocketAddress("localhost",8080);
SocketChannel sc1 = new SocketChannel.open(isa);
SocketChannel sc2 = new SocketChannel.open(isa);
exec.execute(new Demo(sc1));
Future<?> f = exec.submit(new Demo(sc2));
f.cancel(true); //可以終止sc1通道所在的執行緒;
exec.shutdownNow(); //可以終止exec執行緒池內所有的執行緒;
sc1.close();
sc2.close();
}
}
3)中斷④類被互斥阻塞的執行緒
使用Thread.iterrupt方法無法中斷互斥類執行緒,
解決方式1:可以使用ReentrantLock顯式加鎖,在JavaSE5中引入的新特性,ReentrantLock上阻塞的任務可以被中斷;
class Task imlements Runnable{
private Lock lock = new ReentrantLock();
public void run(){
lock.lock();
try{
while(true)
}catch(InterruptedExcpetion e){
System.out.println("The Task is interrupted!");
}finally{
lock.unlock();
}
}
public void main(){
Thread t = new Thread(new Task());
t.start();
t.interrupt();
}
}
解決方式2:使用一個while(!Thread.interrupted())包裹同步的程式碼塊
class Task impelments Runnable{
private synchronized void method1(){ }
public void run(){
try{
whlie(!Thread.interrupted())
method1();
}catch(InteruptedException e){
}
}
public static void main(){
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Task());
exec.shutdownNow(); //執行緒被打斷
/*或 Thread t = new Thread(new Task());
t.start();
t.interrupt(); */
}
}