(歡迎關注微信公衆號:深入Java底層)
1、停止線程
1.1 停止不了的線程
調用interrupt()方法僅僅是在當前線程中打了一個停止的標記,並不是真的停止線程。
1.2 判斷線程是否是停止狀態
this.interrupted():測試當前線程是否已經是中斷狀態,執行後具有將狀態標誌清除爲false的功能。
package t12;
publicclass MyThread extends Thread {
@Override
publicvoid run() {
super.run();
for(int i=0;i<500000;i++){
System.out.println("i="+ (i+1));
}
}
}
package t12;
publicclass Run2 {
/**
* @param args
*/
publicstaticvoidmain(String[] args) {
//thread.interrupt();
Thread.currentThread().interrupt();
System.out.println("是否停止1? =" + Thread.interrupted());
System.out.println("是否停止2? =" + Thread.interrupted());
System.out.println("end!");
}
}
運行結果:
//thread.interrupt();
是否停止1? =false
是否停止2? =false
end!
// Thread.currentThread().interrupt();
是否停止1? =true
是否停止2? =false
end!
this.isInterrupted():測試線程Thread對象是否已經是中斷狀態,但不清除狀態標誌。
package t12;
publicclass Run3 {
/**
* @param args
*/
publicstaticvoidmain(String[] args) {
try {
MyThreadthread = new MyThread();
thread.start();
Thread.sleep(1000);
thread.interrupt();
//Thread.currentThread().interrupt();
System.out.println(" 是否停止1? =" +thread.isInterrupted());
System.out.println(" 是否停止2? =" +thread.isInterrupted());
} catch(InterruptedException e) {
System.out.println("maincatch");
e.printStackTrace();
}
System.out.println("end!");
}
}
運行結果:
//thread.interrupt();
是否停止1? =true
是否停止2? = true
end!
1.3 異常法停止的線程
在線程中用for語句來判斷一下線程是否停止狀態,如果是停止狀態,則後面的代碼不再運行即可。但如果for語句下面還有語句,還是會繼續運行。使用“拋異常”的方法可以解決上面的問題,參看如下代碼。
package t13_1;
publicclass Run {
publicstaticvoidmain(String[] args) {
try {
MyThreadthread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("maincatch");
e.printStackTrace();
}
System.out.println("end!");
}
}
package t13_1;
publicclass Run {
publicstaticvoidmain(String[] args) {
try {
MyThreadthread = new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("maincatch");
e.printStackTrace();
}
System.out.println("end!");
}
/**
* 運行結果:
* ...
i=352988
i=352989
i=352990
i=352991
i=352992
i=352993
已經停止狀態了,我要退出了
end!
進MyThread.java類run方法中的catch了!
java.lang.InterruptedException
att13_1.MyThread.run(MyThread.java:11)
*
*/
}
1.4 在沉睡中停止
如果在sleep狀態下停止某一線程,會進入catch語句,並且清除停止狀態值,使之變成false;
package t14;
publicclass MyThread extends Thread {
@Override
publicvoid run() {
super.run();
try{
System.out.println("runbegin");
Thread.sleep(200000);
System.out.println("runend");
}catch(InterruptedExceptione){
System.out.println("在沉睡中被停止!進入catch!" + Thread.interrupted());
e.printStackTrace();
}
}
}
package t14;
publicclass Run {
/**
* @param args
*/
publicstaticvoidmain(String[] args) {
try {
MyThreadthread = new MyThread();
thread.start();
Thread.sleep(200);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("maincatch");
e.printStackTrace();
}
System.out.println("end!");
}
/**
* 運行結果:
* run begin
end!
在沉睡中被停止!進入catch!false
java.lang.InterruptedException: sleepinterrupted
at java.lang.Thread.sleep(Native Method)
at t14.MyThread.run(MyThread.java:10)
*
*/
}
如果先interrupt()然後再sleep,也會進入catch語句,並且清除停止狀態值,使之變成false。
package t15;
publicclass MyThread extends Thread {
@Override
publicvoid run() {
super.run();
try{
for(inti=0;i<100000;i++){
System.out.println("i="+(i+1));
}
System.out.println("runbegin");
Thread.sleep(200000);
System.out.println("runend");
}catch(InterruptedExceptione){
System.out.println("先停止!再遇到了sleep!進入catch!"+ Thread.interrupted());
e.printStackTrace();
}
}
/**
* 先interrupt()然後再sleep,也會進入catch語句,並且清除停止狀態值。
*
*/
}
package t15;
publicclass Run {
/**
* @param args
*/
publicstaticvoidmain(String[] args) {
MyThreadthread = new MyThread();
thread.start();
thread.interrupt();
System.out.println("end!");
}
/**
* 運行結果:
* …………….
* i=99995
i=99996
i=99997
i=99998
i=99999
i=100000
runbegin
先停止!再遇到了sleep!進入catch!false
java.lang.InterruptedException:sleep interrupted
atjava.lang.Thread.sleep(Native Method)
att15.MyThread.run(MyThread.java:13)
*
*/
}
1.5 使用return停止線程
將方法interrupt()與return結合使用也能實現停止線程的效果。不過還是建議使用“拋異常”的方法來實現線程的停止,因爲在catch塊中還可以將異常向上拋,使線程停止的事件得以傳播。
2. yield方法
yield()方法的作用是放棄當前的CPU資源,將它讓給其他的任務去佔用CPU執行時間。但放棄的時間不確定,有可能剛剛放棄,馬上又獲得CPU時間片。
3. 線程的優先級
在操作系統中,線程可以劃分優先級,優先級較高的線程得到
的CPU資源較多,也就是CPU優先執行優先級較高的線程對象中任務。
在Java中,線程的優先級具有繼承性,比如A線程啓動B線程,則B線程的優先級與A是一樣的。如果A線程的優先級被更改,B線程將繼承更改。
package t18;
publicclass MyThread1 extends Thread {
@Override
publicvoid run() {
System.out.println("MyThread1run priority=" + this.getPriority());
MyThread2thread2 = new MyThread2();
thread2.start();
}
}
package t18;
publicclass MyThread2 extends Thread {
@Override
publicvoid run() {
System.out.println("MyThread2run priority=" + this.getPriority());
}
}
package t18;
publicclass Run {
/**
* @param args
*/
publicstaticvoidmain(String[] args) {
System.out.println("mainthread begin priority=" + Thread.currentThread().getPriority());
// Thread.currentThread().setPriority(6);
System.out.println("mainthread begin priority=" + Thread.currentThread().getPriority());
MyThread1thread1 = new MyThread1();
thread1.start();
}
/**
* 運行結果:
* main thread begin priority=5
mainthread begin priority=5
MyThread1run priority=5
MyThread2run priority=5
*
* 去掉註釋,運行結果:
* main thread begin priority=5
mainthread begin priority=6
MyThread1run priority=6
MyThread2run priority=6
*
*
* 在java中,線程的優先級具有繼承性,比如A線程啓動B線程,則B線程的優先級與A是一樣的。
*/
}
線程的優先級具有一定的規則性,也就是CPU儘量將執行資源讓給優先級比較高的線程,但優先級較高的線程並不一定每一次都先執行完,線程的優先級還具有“隨機性”。優先級高的運行得快,但是測試的時候好多次並沒有更快。
4. 守護線程
在Java線程中兩種線程,一種是用戶線程,另一種是守護線程。
守護線程是一種特殊的線程,當線程中不存在非守護線程了,則守護線程自動銷燬。典型的守護線程就是垃圾回收線程,當進程中沒有非守護線程了,則垃圾回收線程也就沒有存在的必要了,自動銷燬。Daemon的作用是爲其他線程的運行提供便利服務,守護線程最典型的應用就是GC(垃圾回收器),它就是一個很稱職的守護者。
(歡迎關注微信公衆號:深入Java底層)