java多线程基本概述(二十)——中断
線程中斷我們已經(jīng)直到可以使用?interrupt()?方法,但是你必須要持有?Thread?對象,但是新的并發(fā)庫中似乎在避免直接對?Thread?對象的直接操作,盡量使用?Executor?來執(zhí)行所有的請求。如果你在?ExecutorService?上調(diào)用?shutdownNow()?.那么它將發(fā)送一個?interrupt()?調(diào)用給它啟動的所有線程。如果只是調(diào)用?shutdown()?,則不會發(fā)送中斷。如果只是向中斷某一個任務(wù)呢。如果使用ExcecutorService那么我們通過?submit()?來啟動任務(wù)而不是通過?execut()?來啟動任務(wù),這樣我們可持有該任務(wù)的上下文。?submit()?將返回一個泛型的?Future<?>?對象。持有這個關(guān)鍵字的對象的主要目的即可以接收?call()?方法的返回值,通過?get()?方法,也可以調(diào)用其?cancel()?方法,來中斷某個特定的任務(wù)。。
A Future represents the result of an asynchronous computation. Future 表示異步計算的結(jié)果Methods are provided to check if the computation is complete,to wait for its completion, and to retrieve the result of the computation.
它提供了檢查計算是否完成的方法,以等待計算的完成,并獲取計算的結(jié)果
The result can only be retrieved using method get when the computation has completed,
blocking if necessary until it is ready. Cancellation is performed by the cancel method.
計算完成后只能使用get方法來獲取結(jié)果,如有必要,計算完成前可以阻塞此方法。取消則由cancel方法來執(zhí)行
Additional methods are provided to determine if the task completed normally or was cancelled. Once a computation has completed, the computation cannot be cancelled.
還提供了其他方法,以確定任務(wù)是正常完成還是被取消了。一旦計算完成,就不能再取消計算
If you would like to use a Future for the sake of cancellability but not provide a usable result,
you can declare types of the form Future<?> and return null as a result of the underlying task. Sample Usage (Note that the following classes are all made-up.)
如果為了可取消性而使用?Future?但又不提供可用的結(jié)果,則可以聲明?Future<?>?形式類型、并返回?null?作為底層任務(wù)的結(jié)果。
cancle()api
boolean cancel(boolean mayInterruptIfRunning) Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task. After this method returns, subsequent calls to isDone will always return true. Subsequent calls to isCancelled will always return true if this method returned true. Parameters: mayInterruptIfRunning - true if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete Returns: false if the task could not be cancelled, typically because it has already completed normally; true otherwise 試圖取消對此任務(wù)的執(zhí)行。如果任務(wù)已完成、或已取消,或者由于某些其他原因而無法取消,則此嘗試將失敗。當(dāng)調(diào)用 cancel 時,如果調(diào)用成功,而此任務(wù)尚未啟動,則此任務(wù)將永不運行。如果任務(wù)已經(jīng)啟動,則 mayInterruptIfRunning 參數(shù)確定是否應(yīng)該以試圖停止任務(wù)的方式來中斷執(zhí)行此任務(wù)的線程。 此方法返回后,對 isDone() 的后續(xù)調(diào)用將始終返回 true。如果此方法返回 true,則對 isCancelled() 的后續(xù)調(diào)用將始終返回 true。 參數(shù): mayInterruptIfRunning - 如果應(yīng)該中斷執(zhí)行此任務(wù)的線程,則為 true;否則允許正在運行的任務(wù)運行完成 返回: 如果無法取消任務(wù),則返回 false,這通常是由于它已經(jīng)正常完成;否則返回 true阻塞的種類:
1、等待阻塞:運行的線程執(zhí)行wait()方法,JVM會把該線程放入等待池中。
2、同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。
3、其他阻塞:運行的線程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請求時,JVM會把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉(zhuǎn)入就緒狀態(tài)。
這個例子展示了幾種不同的阻塞
import java.io.IOException; import java.io.InputStream; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit;/*** Created by huaox on 2017/4/20.**/class SleepBlock implements Runnable{@Overridepublic void run() {try {TimeUnit.SECONDS.sleep(100);} catch (InterruptedException e) {System.out.println("InterruptedException by sleep()");}System.out.println("Exiting SleepBlocked.run()");} }class IOBlock implements Runnable{private InputStream inputStream;public IOBlock(InputStream inputStream) {this.inputStream = inputStream;}@Overridepublic void run() {try {System.out.println("Waiting for read(): ");inputStream.read();} catch (IOException e) {if(Thread.currentThread().isInterrupted()){System.out.println("");}else{System.out.println("DON'T Interrupted from block IO");throw new RuntimeException(e);}}System.out.println("Exiting IOBlocked.run()");} } //同步阻塞 class SynchronizedBlock implements Runnable{synchronized void f(){ //永遠不釋放鎖while (true)Thread.yield();}public SynchronizedBlock() {new Thread(){@Overridepublic void run() {f();}}.start();}@Overridepublic void run() {System.out.println("outer thread trying to call f()");f();System.out.println("Exiting SynchronizedBlock.run()");} }public class Interrupting {private static ExecutorService executorService = Executors.newCachedThreadPool();static void test(Runnable runnable) throws InterruptedException{Future<?> future = executorService.submit(runnable);TimeUnit.MILLISECONDS.sleep(100);System.out.println("interrupting "+runnable.getClass().getName());future.cancel(true);System.out.println("interrupt sent to "+runnable.getClass().getName());}public static void main(String[] args) throws InterruptedException {test(new SleepBlock());test(new IOBlock(System.in));test(new SynchronizedBlock());TimeUnit.SECONDS.sleep(3);/* System.out.println("Aborting with System.exit(0)");System.exit(0);*/} }下面分別測試SleepBlock,IOBlock,SynchronizedBlock。運行結(jié)果
SleepBlock:可中斷阻塞
interrupting SleepBlock InterruptedException by sleep() Exiting SleepBlocked.run() interrupt sent to SleepBlock Aborting with System.exit(0)Process finished with exit code 0IOBlock:不可中斷阻塞
Waiting for read(): interrupting IOBlock interrupt sent to IOBlock Aborting with System.exit(0)Process finished with exit code 0SynchronizedBlock:不可中斷阻塞
outer thread trying to call f() interrupting SynchronizedBlock interrupt sent to SynchronizedBlock Aborting with System.exit(0)Process finished with exit code 0從輸出中可以看到,你能夠中斷對sleep()的調(diào)用,(或者任何要求拋出InterrptedException的調(diào)用)。但是,你不能中斷正在視圖獲取synvhronized鎖或者視圖執(zhí)行I/O操作的線程。但是對于IO。可以使用一個比較笨拙的方法。即關(guān)閉任務(wù)在其發(fā)生阻塞的底層資源。
import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit;/*** Created by huaox on 2017/4/20.**/ public class CloseResource {public static void main(String[] args) throws Exception {ExecutorService executorService = Executors.newCachedThreadPool();ServerSocket serverSocket = new ServerSocket(8888);InputStream socketInput = new Socket("localhost",8888).getInputStream();executorService.execute(new IOBlock(socketInput));//executorService.execute(new IOBlock(System.in)); TimeUnit.MILLISECONDS.sleep(100);System.out.println("shutting down all thread");executorService.shutdownNow();TimeUnit.SECONDS.sleep(1);System.out.println("Closing "+ serverSocket.getClass().getName());serverSocket.close();/* TimeUnit.SECONDS.sleep(1);System.out.println("Closing "+ System.in.getClass().getName());System.in.close();*/} }輸出結(jié)果:對于serverSocket.可以關(guān)閉底層資源關(guān)閉
Waiting for read(): shutting down all thread Closing java.net.ServerSocket InterruptedException by block IO Exiting IOBlocked.run() Closing java.io.BufferedInputStreamProcess finished with exit code 0程序正常終止,小紅點變灰。如果對于文件IO。
import java.io.File; import java.io.FileInputStream; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit;/*** Created by huaox on 2017/4/20.**/ public class CloseResource {public static void main(String[] args) throws Exception {ExecutorService executorService = Executors.newCachedThreadPool();FileInputStream fileInputStream = new FileInputStream(new File("D:\\soft\\CCleaner.exe"));/*ServerSocket serverSocket = new ServerSocket(8888);InputStream socketInput = new Socket("localhost",8888).getInputStream();*///executorService.execute(new IOBlock(socketInput));//executorService.execute(new IOBlock(System.in));executorService.execute(new IOBlock(fileInputStream));TimeUnit.MILLISECONDS.sleep(100);System.out.println("shutting down all thread");executorService.shutdownNow();/* TimeUnit.SECONDS.sleep(1);System.out.println("Closing "+ serverSocket.getClass().getName());serverSocket.close();*/TimeUnit.SECONDS.sleep(1);System.out.println("Closing "+ fileInputStream.getClass().getName());System.in.close();} }輸出結(jié)果:
Waiting for read(): Exiting IOBlocked.run() shutting down all thread Closing java.io.FileInputStreamProcess finished with exit code 0也是可以關(guān)閉的。但我們應(yīng)該用NIO更好的進行控制。
/*** Created by huaox on 2017/4/20.**/ class NIOBlock implements Runnable{private final SocketChannel socketChannel;public NIOBlock( SocketChannel socketChannel) {this.socketChannel = socketChannel;}@Overridepublic void run() {try {System.out.println("Waiting for read(): "+this);socketChannel.read(ByteBuffer.allocate(1));}catch (ClosedByInterruptException e) {System.out.println("ClosedByInterruptException");}catch (AsynchronousCloseException e){System.out.println("AsynchronousCloseException");}catch (IOException e){System.out.println("IOException");}System.out.println("Exiting NIOBlocked.run() "+this);} } public class CloseResource {public static void main(String[] args) throws Exception {testNIO();}static void testNIO() throws Exception {ExecutorService executorService = Executors.newCachedThreadPool();ServerSocket serverSocket = new ServerSocket(8888);InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 8888);SocketChannel socketChannel1 = SocketChannel.open(inetSocketAddress);SocketChannel socketChannel2 = SocketChannel.open(inetSocketAddress);Future<?> future = executorService.submit(new NIOBlock(socketChannel1));executorService.execute(new NIOBlock(socketChannel2));executorService.shutdown();TimeUnit.SECONDS.sleep(1);future.cancel(true);TimeUnit.SECONDS.sleep(1);socketChannel2.close();} }輸出結(jié)果:
Waiting for read(): NIOBlock@5cb03462 Waiting for read(): NIOBlock@6b033b12 ClosedByInterruptException //對應(yīng)submit()提交后調(diào)用Future的cancle(true)方法。 Exiting NIOBlocked.run() NIOBlock@5cb03462 AsynchronousCloseException 對用execute()提交后調(diào)用關(guān)閉系統(tǒng)底層資源的close()方法 Exiting NIOBlocked.run() NIOBlock@6b033b12Process finished with exit code 0對于?Channel?,如果通過?submit()?提交,那么可以使用?Future?的?cancel(true)?方法關(guān)閉,得到的異常是
?ClosedByInterruptException?。如果是通過?execute()?提交,那么只能使用資源的?close()?方法進行關(guān)閉,得到的異常是?AsynchronousCloseException?.
所以綜上:我們最好使用?ExecutorService?的? Future<?> submit(Runnable task);?并且使用NIO.
就像前面你在不可中斷I/O中或者等待同步鎖中所觀察到的那樣,無論任何時刻,只要任務(wù)以不可中斷的方式被阻塞,那么都有潛在的會鎖住程序的可能,但是我們直到,在JDK5中,添加以了個特性。
即在?ReentrantLock?上阻塞的任務(wù)具備可以被中斷的能力。這與?synchronized?方法或者臨界區(qū)上阻塞的任務(wù)完全不同。
例子如下:
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;/*** Created by huaox on 2017/4/20.**/class BlockedMutex{private Lock lock = new ReentrantLock();BlockedMutex() {lock.lock();}void f(){try {lock.lockInterruptibly();//這個方法具有可被中斷的能力System.out.println("lock acquired in f()");} catch (InterruptedException e) {System.out.println("interrupted from lock acquisition in f()");}} } class Blocked2 implements Runnable{BlockedMutex mutex = new BlockedMutex();@Overridepublic void run() {System.out.println("waiting for f() in BlockedMutex");mutex.f();System.out.println("broken out of mutex call");} } public class Interrupting2 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(new Blocked2());thread.start();TimeUnit.SECONDS.sleep(1);System.out.println("call thread.interrupt");thread.interrupt();} }輸出結(jié)果:
waiting for f() in BlockedMutex call thread.interrupt interrupted from lock acquisition in f() broken out of mutex callProcess finished with exit code 0可以看到使用?Lock?的?public void lockInterruptibly() throws InterruptedException?時其具有可被中斷的能力
所以我們以后最好不要使用?synchronized?而使用Lock
轉(zhuǎn)載于:https://www.cnblogs.com/soar-hu/p/6739189.html
總結(jié)
以上是生活随笔為你收集整理的java多线程基本概述(二十)——中断的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python面向对象进阶及类成员
- 下一篇: linux下使用C++ Json库