一、daemonthread概述
daemon thread(守護線程)是一種在後台運行的線程。當所有的非守護線程結束時,守護線程隨着JVM一起關閉。一般情況下,守護線程用於執行一些後台任務,比如定期清理垃圾、檢查網絡連接等。
守護線程可以通過 Thread.setDaemon(true) 來設置線程為守護線程,但是必須在調用 start() 方法啟動線程之前設置。
public class DaemonThreadExample extends Thread { public void run() { if (Thread.currentThread().isDaemon()) { System.out.println("This is a daemon thread."); } else { System.out.println("This is not a daemon thread."); } } public static void main(String[] args) { DaemonThreadExample t1 = new DaemonThreadExample(); DaemonThreadExample t2 = new DaemonThreadExample(); t1.setDaemon(true); // 設置為守護線程 t1.start(); t2.start(); } }
二、daemon thread的特點
守護線程有以下特點:
1.守護線程在非守護線程結束時自動結束
當所有的非守護線程結束時,JVM 會檢查是否還有守護線程在運行,如果沒有,則自動退出。因此,守護線程不應該被用來執行需要確保完成的操作,比如寫文件等。
2.守護線程自動被設置為低優先級
當一個線程啟動時,它會繼承其父線程的優先級。但是,守護線程會被自動設置為低優先級,這意味着它們會被優先調度用於執行回收垃圾等不太重要的任務。
3.守護線程不能持有任何鎖
因為守護線程會在非守護線程結束時自動結束,如果它持有鎖,那麼其他線程就無法再獲得該鎖,這會造成死鎖。
三、如何使用daemonthread
1.線程池中使用
可以在線程池中創建守護線程,這樣就可以方便地管理和控制守護線程。
public class DaemonThreadPoolExample { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread thread = new Thread(r); thread.setDaemon(true); // 設置為守護線程 return thread; } }); executorService.submit(() -> { while (true) { System.out.println("daemon thread is running in the thread pool."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread.sleep(5000); executorService.shutdown(); } }
2.後台任務調度
比如定期檢查數據庫連接池是否滿足要求等任務可以使用守護線程來執行。下面的代碼演示了如何使用 ScheduledThreadPoolExecutor 定期執行一段後台任務。
public class DaemonScheduledExecutorExample { public static void main(String[] args) { ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); executor.setRemoveOnCancelPolicy(true); // 守護線程需要設置此屬性為true,表示從任務隊列中刪除已取消的任務 ScheduledFuture future = executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("Background task is running."); } }, 0, 1, TimeUnit.SECONDS); executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); // 確保shutdown後不再執行delayed任務 executor.setKeepAliveTime(10, TimeUnit.SECONDS); // 設置線程空閑超時時間 executor.allowCoreThreadTimeOut(true); // 允許核心線程超時關閉 // 等待5秒鐘,然後取消任務 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } future.cancel(true); executor.shutdown(); } }
四、daemonthread使用的注意事項
1.不要將需要確保完成的操作放在守護線程中執行
因為守護線程會隨着JVM一起關閉,如果需要確保任務完成,不能使用守護線程。
2.不要在守護線程中使用sleep()方法
因為當JVM退出時,守護線程可能會被強制中斷,在sleep()期間中斷會拋出InterruptedException異常。
3.不要讓守護線程持有任何鎖
因為守護線程會在非守護線程結束時自動結束,如果它持有鎖,那麼其他線程就無法再獲得該鎖,這會造成死鎖。
4.守護線程無法在main方法結束後繼續執行
因為當main方法結束時,JVM會嘗試停止所有線程。如果所有的非守護線程都結束了,守護線程也會被停止。
5.需要使用內存屏障來同步數據訪問
因為守護線程的優先級低,因此在數據訪問時很可能會出現並發問題。可以使用內存屏障來同步數據訪問,保證代碼的正確性。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/246752.html