(轉)Java中的守護執行緒 Java的守護執行緒與非守護執行緒
Java的守護執行緒與非守護執行緒
守護執行緒與非守護執行緒
最近在看多執行緒的Timer章節,發現運用到了守護執行緒,感覺Java的基礎知識還是需要補充。
Java分為兩種執行緒:使用者執行緒和守護執行緒
所謂守護執行緒是指在程式執行的時候在後臺提供一種通用服務的執行緒,比如垃圾回收執行緒就是一個很稱職的守護者,並且這種執行緒並不屬於程式中不可或缺的部分。因 此,當所有的非守護執行緒結束時,程式也就終止了,同時會殺死程序中的所有守護執行緒。反過來說,只要任何非守護執行緒還在執行,程式就不會終止。
守護執行緒和使用者執行緒的沒啥本質的區別:唯一的不同之處就在於虛擬機器的離開:如果使用者執行緒已經全部退出執行了,只剩下守護執行緒存在了,虛擬機器也就退出了。 因為沒有了被守護者,守護執行緒也就沒有工作可做了,也就沒有繼續執行程式的必要了。
將執行緒轉換為守護執行緒可以通過呼叫Thread物件的setDaemon(true)方法來實現。在使用守護執行緒時需要注意一下幾點:
(1) thread.setDaemon(true)必須在thread.start()之前設定,否則會跑出一個IllegalThreadStateException異常。你不能把正在執行的常規執行緒設定為守護執行緒。
(2) 在Daemon執行緒中產生的新執行緒也是Daemon的。
(3) 守護執行緒應該永遠不去訪問固有資源,如檔案、資料庫,因為它會在任何時候甚至在一個操作的中間發生中斷。
Timer程式碼示例:
import java.util.Date;
import java.util.TimerTask;
public class MyTask extends TimerTask { @Override public void run() { System.out.println("任務執行了,時間為:"+new Date()); }
主函式
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
public class Test1 {
public static void main(String[] args){ System.out.println("當前時間:"+new Date()); Calendar calendar=Calendar.getInstance(); calendar.add(Calendar.SECOND,10); Date date=calendar.getTime(); MyTask task=new MyTask(); Timer timer=new Timer(); timer.schedule(task,date); } }
執行結果:
當前時間:Sat Jun 03 11:47:40 CST 2017 任務執行了,時間為:Sat Jun 03 11:47:50 CST 2017
任務雖然執行完了,但程序還未銷燬,呈紅色狀態,為什麼會出現這種情況呢?
可以看一下Timer的原始碼
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(String name) { thread.setName(name); thread.start(); }
可以看出每建立一個Timer就是啟動一個新的執行緒,那麼啟動的執行緒不是守護執行緒,所以一直執行。將新建立的的Timer改成守護執行緒,更改如上的程式碼:
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
public class Test1 {
public static void main(String[] args){ System.out.println("當前時間:"+new Date()); Calendar calendar=Calendar.getInstance(); calendar.add(Calendar.SECOND,10); Date date=calendar.getTime(); MyTask task=new MyTask(); Timer timer=new Timer(true); timer.schedule(task,date); } }
執行結果如下:
當前時間:Sat Jun 03 11:47:40 CST 2017
守護執行緒中產生的執行緒也是守護執行緒
如下示例:
public class Daemon implements Runnable { private Thread[] t = new Thread[10]; @Override public void run() { for (int i=0; i<t.length; i++) { t[i] = new Thread(new DaemonSpawn()); t[i].start(); System.out.println("DaemonSpawn " + i + " started."); } for (int i=0; i<t.length; i++) { System.out.println("t[" + i + "].isDaemon() = " + t[i].isDaemon() + "."); } while (true) { Thread.yield(); } } }
類DaemonSpawn:
public class DaemonSpawn implements Runnable { @Override public void run() { while (true) { Thread.yield(); } } }
主函式:
import java.util.concurrent.TimeUnit;
public class Test1 { public static void main(String[] args) throws InterruptedException { Thread d = new Thread(new Daemon()); d.setDaemon(true); //必須在啟動執行緒前呼叫 d.start(); System.out.println("d.isDaemon() = " + d.isDaemon() + "."); TimeUnit.SECONDS.sleep(1); } }
執行結果如圖:
d.isDaemon() = true.
DaemonSpawn 0 started.
DaemonSpawn 1 started.
DaemonSpawn 2 started.
DaemonSpawn 3 started. DaemonSpawn 4 started. DaemonSpawn 5 started. DaemonSpawn 6 started. DaemonSpawn 7 started. DaemonSpawn 8 started. DaemonSpawn 9 started. t[0].isDaemon() = true. t[1].isDaemon() = true. t[2].isDaemon() = true. t[3].isDaemon() = true. t[4].isDaemon() = true. t[5].isDaemon() = true. t[6].isDaemon() = true. t[7].isDaemon() = true. t[8].isDaemon() = true. t[9].isDaemon() = true. Process finished with exit code 0
如果將mian函式中的TimeUnit.SECONDS.sleep(1);註釋掉,看一下TimeUnit.SECONDS.sleep()的原始碼:
public void sleep(long timeout) throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); Thread.sleep(ms, ns); } }
其實就是對Thread.sleep()的封裝,提供了可讀性更好的執行緒暫停操作
註釋後代碼執行如下:
d.isDaemon() = true.
DaemonSpawn 0 started.
DaemonSpawn 1 started.
DaemonSpawn 2 started.
DaemonSpawn 3 started. DaemonSpawn 4 started. DaemonSpawn 5 started. DaemonSpawn 6 started. DaemonSpawn 7 started. DaemonSpawn 8 started. DaemonSpawn 9 started.
以上結果也說明了如果使用者執行緒全部退出了,只剩下守護執行緒存在了,虛擬機器也就退出了。
標籤: Java多執行緒守護執行緒與非守護執行緒
最近在看多執行緒的Timer章節,發現運用到了守護執行緒,感覺Java的基礎知識還是需要補充。
Java分為兩種執行緒:使用者執行緒和守護執行緒
所謂守護執行緒是指在程式執行的時候在後臺提供一種通用服務的執行緒,比如垃圾回收執行緒就是一個很稱職的守護者,並且這種執行緒並不屬於程式中不可或缺的部分。因 此,當所有的非守護執行緒結束時,程式也就終止了,同時會殺死程序中的所有守護執行緒。反過來說,只要任何非守護執行緒還在執行,程式就不會終止。
守護執行緒和使用者執行緒的沒啥本質的區別:唯一的不同之處就在於虛擬機器的離開:如果使用者執行緒已經全部退出執行了,只剩下守護執行緒存在了,虛擬機器也就退出了。 因為沒有了被守護者,守護執行緒也就沒有工作可做了,也就沒有繼續執行程式的必要了。
將執行緒轉換為守護執行緒可以通過呼叫Thread物件的setDaemon(true)方法來實現。在使用守護執行緒時需要注意一下幾點:
(1) thread.setDaemon(true)必須在thread.start()之前設定,否則會跑出一個IllegalThreadStateException異常。你不能把正在執行的常規執行緒設定為守護執行緒。
(2) 在Daemon執行緒中產生的新執行緒也是Daemon的。
(3) 守護執行緒應該永遠不去訪問固有資源,如檔案、資料庫,因為它會在任何時候甚至在一個操作的中間發生中斷。
Timer程式碼示例:
import java.util.Date;
import java.util.TimerTask;
public class MyTask extends TimerTask { @Override public void run() { System.out.println("任務執行了,時間為:"+new Date()); }
主函式
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
public class Test1 {
public static void main(String[] args){ System.out.println("當前時間:"+new Date()); Calendar calendar=Calendar.getInstance(); calendar.add(Calendar.SECOND,10); Date date=calendar.getTime(); MyTask task=new MyTask(); Timer timer=new Timer(); timer.schedule(task,date); } }
執行結果:
當前時間:Sat Jun 03 11:47:40 CST 2017 任務執行了,時間為:Sat Jun 03 11:47:50 CST 2017
任務雖然執行完了,但程序還未銷燬,呈紅色狀態,為什麼會出現這種情況呢?
可以看一下Timer的原始碼
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(String name) { thread.setName(name); thread.start(); }
可以看出每建立一個Timer就是啟動一個新的執行緒,那麼啟動的執行緒不是守護執行緒,所以一直執行。將新建立的的Timer改成守護執行緒,更改如上的程式碼:
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
public class Test1 {
public static void main(String[] args){ System.out.println("當前時間:"+new Date()); Calendar calendar=Calendar.getInstance(); calendar.add(Calendar.SECOND,10); Date date=calendar.getTime(); MyTask task=new MyTask(); Timer timer=new Timer(true); timer.schedule(task,date); } }
執行結果如下:
當前時間:Sat Jun 03 11:47:40 CST 2017
守護執行緒中產生的執行緒也是守護執行緒
如下示例:
public class Daemon implements Runnable { private Thread[] t = new Thread[10]; @Override public void run() { for (int i=0; i<t.length; i++) { t[i] = new Thread(new DaemonSpawn()); t[i].start(); System.out.println("DaemonSpawn " + i + " started."); } for (int i=0; i<t.length; i++) { System.out.println("t[" + i + "].isDaemon() = " + t[i].isDaemon() + "."); } while (true) { Thread.yield(); } } }
類DaemonSpawn:
public class DaemonSpawn implements Runnable { @Override public void run() { while (true) { Thread.yield(); } } }
主函式:
import java.util.concurrent.TimeUnit;
public class Test1 { public static void main(String[] args) throws InterruptedException { Thread d = new Thread(new Daemon()); d.setDaemon(true); //必須在啟動執行緒前呼叫 d.start(); System.out.println("d.isDaemon() = " + d.isDaemon() + "."); TimeUnit.SECONDS.sleep(1); } }
執行結果如圖:
d.isDaemon() = true.
DaemonSpawn 0 started.
DaemonSpawn 1 started.
DaemonSpawn 2 started.
DaemonSpawn 3 started. DaemonSpawn 4 started. DaemonSpawn 5 started. DaemonSpawn 6 started. DaemonSpawn 7 started. DaemonSpawn 8 started. DaemonSpawn 9 started. t[0].isDaemon() = true. t[1].isDaemon() = true. t[2].isDaemon() = true. t[3].isDaemon() = true. t[4].isDaemon() = true. t[5].isDaemon() = true. t[6].isDaemon() = true. t[7].isDaemon() = true. t[8].isDaemon() = true. t[9].isDaemon() = true. Process finished with exit code 0
如果將mian函式中的TimeUnit.SECONDS.sleep(1);註釋掉,看一下TimeUnit.SECONDS.sleep()的原始碼:
public void sleep(long timeout) throws InterruptedException { if (timeout > 0) { long ms = toMillis(timeout); int ns = excessNanos(timeout, ms); Thread.sleep(ms, ns); } }
其實就是對Thread.sleep()的封裝,提供了可讀性更好的執行緒暫停操作
註釋後代碼執行如下:
d.isDaemon() = true.
DaemonSpawn 0 started.
DaemonSpawn 1 started.
DaemonSpawn 2 started.
DaemonSpawn 3 started. DaemonSpawn 4 started. DaemonSpawn 5 started. DaemonSpawn 6 started. DaemonSpawn 7 started. DaemonSpawn 8 started. DaemonSpawn 9 started.
以上結果也說明了如果使用者執行緒全部退出了,只剩下守護執行緒存在了,虛擬機器也就退出了。