《Java多執行緒程式設計核心技術》(一)
概要:
學習使用Thread.currentThread()
瞭解中斷執行緒的方法
瞭解sleep
方法丟擲異常
Thread.currentThread()
Thread.currentThread()
方法可返回程式碼正在被哪個執行緒呼叫的資訊。
public class Counter extends Thread {
//構造方法在主執行緒中被執行
public Counter() {
print("constructor begin");
print("Thread.currentThread().getName()------" +Thread.currentThread().getName());//main
print("this.getName()-----------"+this.getName());//Thread-0
print("constructor end");
}
@Override
public void run() {
//在子執行緒中被執行
print("run begin");
print("Thread.currentThread().getName()--------"+Thread.currentThread().getName());
print("this.getName()--------" +this.getName());
print("run end");
}
private void print(String msg){
System.out.println(msg);
}
}
public class Run {
public static void main(String[] args){
Counter counter = new Counter();
Thread t = new Thread(counter);
t.setName("new" );
t.start();
}
}
/** 執行結果如下:
constructor begin
Thread.currentThread().getName()------main
this.getName()-----------Thread-0
constructor end
run begin
Thread.currentThread().getName()--------new
this.getName()--------Thread-0
run end
*/
如上,Counter
構造方法是在main
執行緒中執行。run()
方法是在new
執行緒中執行的。
this.getName()
中this
指代的是Counter
例項,Counter
繼承Thread
,在初始化會設定名稱為Thread-0
。
第二個執行緒t
初始化,名稱預設為Thread-1
,後續重新賦值為new
。
停止執行緒
有三種方法可以使終止執行緒。
1. 使用退出標誌,使執行緒正常退出,也就是當run方法完成後執行緒終止。
2. 使用stop方法強行終止執行緒(這個方法不推薦使用,因為stop和suspend、resume一樣,也可能發生不可預料的結果)。
3. 使用interrupt方法中斷執行緒。
interrupt()方法僅僅是在當前執行緒中打了一個停止的標記,並不是真的停止執行緒
換句話說,呼叫該方法的執行緒會被設定一個“中斷”狀態,用於判斷的中斷狀態的方法如果返回true說明中斷狀態被設定了。
如何判斷執行緒的狀態是不是停止的?Thread.java
類裡提供了兩種方法:
1)this.interrupted()
: 測試當前執行緒是否已經是中斷狀態,執行後具有將狀態標誌置為false的功能。如果這個方法被連續呼叫兩次,第二次呼叫將返回false。
2)this.isInterrupted()
: 測試執行緒Thread物件是否已經是中斷狀態,但不清除狀態標識。
第一種方法,判斷當前執行緒的狀態;第二個方法,判斷呼叫者的中斷狀態。
原始碼:
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private native boolean isInterrupted(boolean ClearInterrupted);
從原始碼中可以看出,最終呼叫的是isInterrupted(boolean ClearInterrupted)
方法,引數ClearInterrupted
可以控制中斷狀態清除。
驗證1:
如下程式碼雖然呼叫了interrupted()方法,但是從執行結果來看,執行緒並未停止。
class MyThread extends Thread{
@Override
public void run() {
for(int i =0;i<1000;i++){
System.out.println("number"+i);
}
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
//主執行緒執行10毫秒之後,中斷子執行緒t。但是並沒有效果。僅僅是打了一個標記
Thread.sleep(10);
t.interrupt();
}
}
驗證2:
從執行結果可以看出,t.interrupted()
返回的是當前執行緒的狀態,即main
執行緒,main
從未呼叫過interrupt()
方法,未被標記過狀態,因此返回的結果都是false
。
t.isInterrupted()
返回的是t執行緒的中斷狀態。主執行緒執行10毫秒之後,呼叫中斷方法,此時返回狀態為true
,表示t.interrupt()
方法生效了。
public class Run {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
//主執行緒執行10毫秒之後,中斷子執行緒t。
Thread.sleep(10);
t.interrupt();
System.out.println("當前執行緒0:"+t.interrupted());
System.out.println("停止執行緒1:"+t.isInterrupted());
Thread.sleep(1000);
System.out.println("當前執行緒0:"+t.interrupted());
System.out.println("停止執行緒1:"+t.isInterrupted());
}
}
/**
當前執行緒0:false
停止執行緒1:true
當前執行緒0:false
停止執行緒1:false
*/
驗證3:
連續兩次呼叫interrupted()
方法,第二次呼叫將返回false
public class Run {
public static void main(String[] args) throws InterruptedException {
Thread.currentThread().interrupt();
System.out.println("停止執行緒:"+Thread.currentThread().interrupted());
System.out.println("停止執行緒:"+Thread.currentThread().interrupted());
}
}
/**
停止執行緒:true
停止執行緒:false
*/
應用
將interrupt()
方法和isInterrupted()
方法結合使用,來停止執行緒。
1.使用break停止執行緒
public class Counter0 extends Thread {
@Override
public void run() {
super.run();
for (int i = 0; i < 100000; i++) {
if(this.isInterrupted()){
System.out.println("已經標記了停止狀態,我要退出");
break;
}
System.out.println("number"+i);
}
System.out.println("退出for迴圈,後面依然執行");
}
public class Run {
public static void main(String[] args){
try {
Counter0 counter0 = new Counter0();
counter0.start();
Thread.sleep(10);
counter0.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
number776
number777
number778
number779
number780
已經標記了停止狀態,我要退出
退出for迴圈,後面依然執行
*/
使用break
的方式並未完全退出子執行緒,for
迴圈之外的程式碼仍然在執行
改進:
2.使用拋異常的方式,停止執行緒執行
public class Counter0 extends Thread {
@Override
public void run() {
try{
for (int i = 0; i < 100000; i++) {
if(this.isInterrupted()){
System.out.println("已經標記了停止狀態,我要退出");
throw new InterruptedException();
}
System.out.println("number"+i);
}
System.out.println("退出for迴圈,後面依然執行");
}catch (InterruptedException e){
System.out.println("捕獲異常");
}
}
}
/**
number983
number984
number985
已經標記了停止狀態,我要退出
捕獲異常
*/
在沉睡中停止執行緒
public class Thread implements Runnable{
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis
* the length of time to sleep in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public static native void sleep(long millis) throws InterruptedException;
}
InterruptedException
當前執行緒睡眠中,如果有任何執行緒中斷了當前執行緒,丟擲異常。當丟擲異常時,當前執行緒的中斷狀態被清除,值為false
舉個栗子:
public class Counter0 extends Thread {
@Override
public void run() {
super.run();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("狀態標記:"+this.isInterrupted());
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args){
try {
Counter0 counter0 = new Counter0();
counter0.start();
Thread.sleep(10);
counter0.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
狀態標記:false
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at com.yolo.thread.Counter0.run(Counter0.java:37)
*/