Thread對象
每個線程都與Thread類的實例相關聯,使用Thread對象創建并發應用程序有兩種基本策略。
要直接控制線程的創建和管理,只需在每次應用程序需要啟動異步任務時實例化Thread。
要從應用程序的其余部分抽象線程管理,請將應用程序的任務傳遞給執行器。
本節介紹Thread對象的使用,Executors將與其他高級并發對象一起討論。
定義和啟動線程創建Thread實例的應用程序必須提供將在該線程中運行的代碼,有兩種方法可以做到這一點:
提供Runnable對象,Runnable接口定義了一個多帶帶的run方法,用于包含在線程中執行的代碼,Runnable對象被傳遞給Thread構造函數,如HelloRunnable示例中所示:
public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } }
子類化Thread,Thread類本身實現了Runnable,盡管它的run方法什么都不做,應用程序可以子類化Thread,提供自己的run實現,如HelloThread示例中所示:
public class HelloThread extends Thread { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new HelloThread()).start(); } }
請注意,兩個示例都調用Thread.start以啟動新線程。
你應該使用哪個語法?使用Runnable對象的第一個語法更通用,因為Runnable對象可以繼承Thread以外的類。第二個語法在簡單的應用程序中更容易使用,但受限于你的任務類必須是Thread的后代這一事實。本課重點介紹第一種方法,該方法將Runnable任務與執行任務的Thread對象分開,這種方法不僅更靈活,而且適用于后面介紹的高級線程管理API。
Thread類定義了許多對線程管理有用的方法,這些包括靜態方法,它們提供關于調用該方法的線程的信息,或影響該線程的狀態。其他方法是從管理線程和Thread對象的其他線程調用的,我們將在以下部分中研究其中一些方法。
用Sleep暫停執行Thread.sleep導致當前線程暫停執行指定的時間段,這是使處理器時間可用于應用程序的其他線程或可能在計算機系統上運行的其他應用程序的有效方法。sleep方法也可以用于調步,如下面的示例所示,和等待具有被理解為具有時間要求的職責的另一個線程,如稍后部分中的SimpleThreads示例。
提供了兩個重載版本的sleep:一個指定毫秒的睡眠時間,一個指定納秒的睡眠時間。但是,這些睡眠時間并不能保證精確,因為它們受到底層操作系統提供的設施的限制,此外,睡眠周期可以通過中斷終止,我們將在后面的部分中看到。在任何情況下,你都不能設想調用sleep會準確地在指定的時間段內暫停該線程。
SleepMessages示例使用sleep以四秒為間隔打印消息:
public class SleepMessages { public static void main(String args[]) throws InterruptedException { String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", "A kid will eat ivy too" }; for (int i = 0; i < importantInfo.length; i++) { //Pause for 4 seconds Thread.sleep(4000); //Print a message System.out.println(importantInfo[i]); } } }
請注意,main聲明拋出InterruptedException,這是一個異常,當sleep處于活動狀態時,另一個線程中斷當前線程時,sleep將拋出,由于此應用程序尚未定義另一個導致中斷的線程,因此無需捕獲InterruptedException。
中斷中斷是指示線程應該停止正在做的事情,并執行其他操作,由程序員決定線程如何響應中斷,但用于終止線程是很常見的,這是本課程中強調的用法。
線程通過調用Thread對象上的interrupt來發送中斷,以便線程被中斷,為使中斷機制正常工作,被中斷的線程必須支持自己的中斷。
支持中斷線程如何支持自己的中斷?這取決于它目前正在做什么,如果線程經常調用拋出InterruptedException的方法,它只會在捕獲該異常后從run方法返回。例如,假設SleepMessages示例中的中心消息循環位于線程的Runnable對象的run方法中,然后可以按如下方式修改它以支持中斷:
for (int i = 0; i < importantInfo.length; i++) { // Pause for 4 seconds try { Thread.sleep(4000); } catch (InterruptedException e) { // We"ve been interrupted: no more messages. return; } // Print a message System.out.println(importantInfo[i]); }
許多拋出InterruptedException的方法(例如sleep)被設計為收到中斷時取消當前操作并立即返回。
如果一個線程長時間運行而不調用拋出InterruptedException的方法呢?那么它必須定期調用Thread.interrupted,如果收到中斷,則返回true,例如:
for (int i = 0; i < inputs.length; i++) { heavyCrunch(inputs[i]); if (Thread.interrupted()) { // We"ve been interrupted: no more crunching. return; } }
在這個簡單的例子中,代碼只是測試中斷,如果收到中斷則退出線程,在更復雜的應用程序中,拋出InterruptedException可能更有意義:
if (Thread.interrupted()) { throw new InterruptedException(); }
這允許中斷處理代碼集中在catch子句中。
中斷狀態標志中斷機制使用稱為中斷狀態的內部標志來實現,調用Thread.interrupt設置此標志,當線程通過調用靜態方法Thread.interrupted來檢查中斷時,將清除中斷狀態,非靜態isInterrupted方法,由一個線程用于查詢另一個線程的中斷狀態,不會更改中斷狀態標志。
按照慣例,任何通過拋出InterruptedException退出的方法都會在執行此操作時清除中斷狀態,但是,通過另一個線程調用中斷,總是可以立即再次設置中斷狀態。
加入join方法允許一個線程等待另一個線程的完成,如果t是其線程當前正在執行的Thread對象:
t.join();
導致當前線程暫停執行,直到t的線程終止,join重載方法允許程序員指定等待周期,但是,與sleep一樣,join依賴于OS進行計時,因此你不應該設想join將準確地等待你指定的時間。
與sleep一樣,join通過InterruptedException退出來響應中斷。
SimpleThreads示例以下示例匯總了本節的一些概念,SimpleThreads由兩個線程組成。第一個是每個Java應用程序都有的主線程,主線程從Runnable對象MessageLoop創建一個新線程,并等待它完成,如果MessageLoop線程需要很長時間才能完成,主線程會中斷它。
MessageLoop線程打印出一系列消息,如果在打印完所有消息之前被中斷,MessageLoop線程將打印一條消息并退出。
public class SimpleThreads { // Display a message, preceded by // the name of the current thread static void threadMessage(String message) { String threadName = Thread.currentThread().getName(); System.out.format("%s: %s%n", threadName, message); } private static class MessageLoop implements Runnable { public void run() { String importantInfo[] = { "Mares eat oats", "Does eat oats", "Little lambs eat ivy", "A kid will eat ivy too" }; try { for (int i = 0; i < importantInfo.length; i++) { // Pause for 4 seconds Thread.sleep(4000); // Print a message threadMessage(importantInfo[i]); } } catch (InterruptedException e) { threadMessage("I wasn"t done!"); } } } public static void main(String args[]) throws InterruptedException { // Delay, in milliseconds before // we interrupt MessageLoop // thread (default one hour). long patience = 1000 * 60 * 60; // If command line argument // present, gives patience // in seconds. if (args.length > 0) { try { patience = Long.parseLong(args[0]) * 1000; } catch (NumberFormatException e) { System.err.println("Argument must be an integer."); System.exit(1); } } threadMessage("Starting MessageLoop thread"); long startTime = System.currentTimeMillis(); Thread t = new Thread(new MessageLoop()); t.start(); threadMessage("Waiting for MessageLoop thread to finish"); // loop until MessageLoop // thread exits while (t.isAlive()) { threadMessage("Still waiting..."); // Wait maximum of 1 second // for MessageLoop thread // to finish. t.join(1000); if (((System.currentTimeMillis() - startTime) > patience) && t.isAlive()) { threadMessage("Tired of waiting!"); t.interrupt(); // Shouldn"t be long now // -- wait indefinitely t.join(); } } threadMessage("Finally!"); } }上一篇:進程和線程 下一篇:同步
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72993.html
摘要:未來的主要發布基于。在中調用函數支持從代碼中直接調用定義在腳本文件中的函數。下面的函數稍后會在端調用為了調用函數,你首先需要將腳本引擎轉換為。調用函數將結果輸出到,所以我們會首先看到輸出。幸運的是,有一套補救措施。 原文:Java 8 Nashorn Tutorial 譯者:飛龍 協議:CC BY-NC-SA 4.0 這個教程中,你會通過簡單易懂的代碼示例,來了解Nashorn Ja...
摘要:在這個示例中我們使用了一個單線程線程池的。在延遲消逝后,任務將會并發執行。這是并發系列教程的第一部分。第一部分線程和執行器第二部分同步和鎖第三部分原子操作和 Java 8 并發教程:線程和執行器 原文:Java 8 Concurrency Tutorial: Threads and Executors 譯者:BlankKelly 來源:Java8并發教程:Threads和Execut...
Lock對象 同步代碼依賴于簡單的可重入鎖,這種鎖易于使用,但有許多限制,java.util.concurrent.locks包支持更復雜的鎖定語法,我們不會詳細檢查這個包,而是將重點放在其最基本的接口Lock上。 Lock對象的工作方式與同步代碼使用的隱式鎖定非常相似,與隱式鎖一樣,一次只有一個線程可以擁有一個Lock對象,Lock對象還通過其關聯的Condition對象支持wait/notif...
摘要:創建一個阻塞隊列生產者生產,目前總共有消費者消費,目前總共有原文鏈接更多教程 原文鏈接 更多教程 本文概要 生產者和消費者問題是線程模型中老生常談的問題,也是面試中經常遇到的問題。光在Java中的實現方式多達數十種,更不用說加上其他語言的實現方式了。那么我們該如何學習呢? 本文會通過精講wait()和notify()方法實現生產者-消費者模型,來學習生產者和消費者問題的原理。 目的...
閱讀 1601·2023-04-26 01:54
閱讀 1630·2021-09-30 09:55
閱讀 2652·2021-09-22 16:05
閱讀 1866·2021-07-25 21:37
閱讀 2628·2019-08-29 18:45
閱讀 1891·2019-08-29 16:44
閱讀 1890·2019-08-29 12:34
閱讀 1352·2019-08-23 14:02