国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

增城微信網(wǎng)站建設公司網(wǎng)絡推廣營銷

增城微信網(wǎng)站建設,公司網(wǎng)絡推廣營銷,微官網(wǎng)怎么制作,wordpress積分下載文章目錄Java 線程基礎線程簡介什么是進程什么是線程進程和線程的區(qū)別創(chuàng)建線程ThreadRunnableCallable、Future、FutureTaskCallableFutureFutureTaskCallable Future FutureTask 示例線程基本用法線程休眠線程禮讓終止線程守護線程線程通信wait/notify/notifyAlljoin管道線程…

文章目錄

  • Java 線程基礎
    • 線程簡介
      • 什么是進程
      • 什么是線程
      • 進程和線程的區(qū)別
    • 創(chuàng)建線程
      • Thread
      • Runnable
      • Callable、Future、FutureTask
        • Callable
        • Future
        • FutureTask
        • Callable + Future + FutureTask 示例
    • 線程基本用法
      • 線程休眠
      • 線程禮讓
      • 終止線程
      • 守護線程
    • 線程通信
      • wait/notify/notifyAll
      • join
      • 管道
    • 線程生命周期
    • 線程常見問題
      • sleep、yield、join 方法有什么區(qū)別
      • 為什么 sleep 和 yield 方法是靜態(tài)的
      • Java 線程是否按照線程優(yōu)先級嚴格執(zhí)行
      • 一個線程兩次調用 start()方法會怎樣
      • `start` 和 `run` 方法有什么區(qū)別
      • 可以直接調用 `Thread` 類的 `run` 方法么
    • 參考資料

Java 線程基礎

關鍵詞:Thread、RunnableCallable、Futurewait、notify、notifyAll、join、sleepyeild、線程狀態(tài)線程通信

線程簡介

什么是進程

簡言之,進程可視為一個正在運行的程序。它是系統(tǒng)運行程序的基本單位,因此進程是動態(tài)的。進程是具有一定獨立功能的程序關于某個數(shù)據(jù)集合上的一次運行活動。進程是操作系統(tǒng)進行資源分配的基本單位。

什么是線程

線程是操作系統(tǒng)進行調度的基本單位。線程也叫輕量級進程(Light Weight Process),在一個進程里可以創(chuàng)建多個線程,這些線程都擁有各自的計數(shù)器、堆棧和局部變量等屬性,并且能夠訪問共享的內(nèi)存變量。

進程和線程的區(qū)別

  • 一個程序至少有一個進程,一個進程至少有一個線程。
  • 線程比進程劃分更細,所以執(zhí)行開銷更小,并發(fā)性更高。
  • 進程是一個實體,擁有獨立的資源;而同一個進程中的多個線程共享進程的資源。

創(chuàng)建線程

創(chuàng)建線程有三種方式:

  • 繼承 Thread
  • 實現(xiàn) Runnable 接口
  • 實現(xiàn) Callable 接口

Thread

通過繼承 Thread 類創(chuàng)建線程的步驟:

  1. 定義 Thread 類的子類,并覆寫該類的 run 方法。run 方法的方法體就代表了線程要完成的任務,因此把 run 方法稱為執(zhí)行體。
  2. 創(chuàng)建 Thread 子類的實例,即創(chuàng)建了線程對象。
  3. 調用線程對象的 start 方法來啟動該線程。
public class ThreadDemo {public static void main(String[] args) {// 實例化對象MyThread tA = new MyThread("Thread 線程-A");MyThread tB = new MyThread("Thread 線程-B");// 調用線程主體tA.start();tB.start();}static class MyThread extends Thread {private int ticket = 5;MyThread(String name) {super(name);}@Overridepublic void run() {while (ticket > 0) {System.out.println(Thread.currentThread().getName() + " 賣出了第 " + ticket + " 張票");ticket--;}}}}

Runnable

實現(xiàn) Runnable 接口優(yōu)于繼承 Thread,因為:

  • Java 不支持多重繼承,所有的類都只允許繼承一個父類,但可以實現(xiàn)多個接口。如果繼承了 Thread 類就無法繼承其它類,這不利于擴展。
  • 類可能只要求可執(zhí)行就行,繼承整個 Thread 類開銷過大。

通過實現(xiàn) Runnable 接口創(chuàng)建線程的步驟:

  1. 定義 Runnable 接口的實現(xiàn)類,并覆寫該接口的 run 方法。該 run 方法的方法體同樣是該線程的線程執(zhí)行體。
  2. 創(chuàng)建 Runnable 實現(xiàn)類的實例,并以此實例作為 Thread 的 target 來創(chuàng)建 Thread 對象,該 Thread 對象才是真正的線程對象。
  3. 調用線程對象的 start 方法來啟動該線程。
public class RunnableDemo {public static void main(String[] args) {// 實例化對象Thread tA = new Thread(new MyThread(), "Runnable 線程-A");Thread tB = new Thread(new MyThread(), "Runnable 線程-B");// 調用線程主體tA.start();tB.start();}static class MyThread implements Runnable {private int ticket = 5;@Overridepublic void run() {while (ticket > 0) {System.out.println(Thread.currentThread().getName() + " 賣出了第 " + ticket + " 張票");ticket--;}}}}

Callable、Future、FutureTask

繼承 Thread 類和實現(xiàn) Runnable 接口這兩種創(chuàng)建線程的方式都沒有返回值。所以,線程執(zhí)行完后,無法得到執(zhí)行結果。但如果期望得到執(zhí)行結果該怎么做?

為了解決這個問題,Java 1.5 后,提供了 Callable 接口和 Future 接口,通過它們,可以在線程執(zhí)行結束后,返回執(zhí)行結果。

Callable

Callable 接口只聲明了一個方法,這個方法叫做 call():

public interface Callable<V> {/*** Computes a result, or throws an exception if unable to do so.** @return computed result* @throws Exception if unable to compute a result*/V call() throws Exception;
}

那么怎么使用 Callable 呢?一般情況下是配合 ExecutorService 來使用的,在 ExecutorService 接口中聲明了若干個 submit 方法的重載版本:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

第一個 submit 方法里面的參數(shù)類型就是 Callable。

Future

Future 就是對于具體的 Callable 任務的執(zhí)行結果進行取消、查詢是否完成、獲取結果。必要時可以通過 get 方法獲取執(zhí)行結果,該方法會阻塞直到任務返回結果。

public interface Future<V> {boolean cancel(boolean mayInterruptIfRunning);boolean isCancelled();boolean isDone();V get() throws InterruptedException, ExecutionException;V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}

FutureTask

FutureTask 類實現(xiàn)了 RunnableFuture 接口,RunnableFuture 繼承了 Runnable 接口和 Future 接口。

所以,FutureTask 既可以作為 Runnable 被線程執(zhí)行,又可以作為 Future 得到 Callable 的返回值。

public class FutureTask<V> implements RunnableFuture<V> {// ...public FutureTask(Callable<V> callable) {}public FutureTask(Runnable runnable, V result) {}
}public interface RunnableFuture<V> extends Runnable, Future<V> {void run();
}

事實上,FutureTask 是 Future 接口的一個唯一實現(xiàn)類。

Callable + Future + FutureTask 示例

通過實現(xiàn) Callable 接口創(chuàng)建線程的步驟:

  1. 創(chuàng)建 Callable 接口的實現(xiàn)類,并實現(xiàn) call 方法。該 call 方法將作為線程執(zhí)行體,并且有返回值。
  2. 創(chuàng)建 Callable 實現(xiàn)類的實例,使用 FutureTask 類來包裝 Callable 對象,該 FutureTask 對象封裝了該 Callable 對象的 call 方法的返回值。
  3. 使用 FutureTask 對象作為 Thread 對象的 target 創(chuàng)建并啟動新線程。
  4. 調用 FutureTask 對象的 get 方法來獲得線程執(zhí)行結束后的返回值。
public class CallableDemo {public static void main(String[] args) {Callable<Long> callable = new MyThread();FutureTask<Long> future = new FutureTask<>(callable);new Thread(future, "Callable 線程").start();try {System.out.println("任務耗時:" + (future.get() / 1000000) + "毫秒");} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}static class MyThread implements Callable<Long> {private int ticket = 10000;@Overridepublic Long call() {long begin = System.nanoTime();while (ticket > 0) {System.out.println(Thread.currentThread().getName() + " 賣出了第 " + ticket + " 張票");ticket--;}long end = System.nanoTime();return (end - begin);}}}

線程基本用法

線程(Thread)基本方法清單:

方法描述
run線程的執(zhí)行實體。
start線程的啟動方法。
currentThread返回對當前正在執(zhí)行的線程對象的引用。
setName設置線程名稱。
getName獲取線程名稱。
setPriority設置線程優(yōu)先級。Java 中的線程優(yōu)先級的范圍是 [1,10],一般來說,高優(yōu)先級的線程在運行時會具有優(yōu)先權。可以通過 thread.setPriority(Thread.MAX_PRIORITY) 的方式設置,默認優(yōu)先級為 5。
getPriority獲取線程優(yōu)先級。
setDaemon設置線程為守護線程。
isDaemon判斷線程是否為守護線程。
isAlive判斷線程是否啟動。
interrupt中斷另一個線程的運行狀態(tài)。
interrupted測試當前線程是否已被中斷。通過此方法可以清除線程的中斷狀態(tài)。換句話說,如果要連續(xù)調用此方法兩次,則第二次調用將返回 false(除非當前線程在第一次調用清除其中斷狀態(tài)之后且在第二次調用檢查其狀態(tài)之前再次中斷)。
join可以使一個線程強制運行,線程強制運行期間,其他線程無法運行,必須等待此線程完成之后才可以繼續(xù)執(zhí)行。
Thread.sleep靜態(tài)方法。將當前正在執(zhí)行的線程休眠。
Thread.yield靜態(tài)方法。將當前正在執(zhí)行的線程暫停,讓其他線程執(zhí)行。

線程休眠

使用 Thread.sleep 方法可以使得當前正在執(zhí)行的線程進入休眠狀態(tài)。

使用 Thread.sleep 需要向其傳入一個整數(shù)值,這個值表示線程將要休眠的毫秒數(shù)。

Thread.sleep 方法可能會拋出 InterruptedException,因為異常不能跨線程傳播回 main 中,因此必須在本地進行處理。線程中拋出的其它異常也同樣需要在本地進行處理。

public class ThreadSleepDemo {public static void main(String[] args) {new Thread(new MyThread("線程A", 500)).start();new Thread(new MyThread("線程B", 1000)).start();new Thread(new MyThread("線程C", 1500)).start();}static class MyThread implements Runnable {/** 線程名稱 */private String name;/** 休眠時間 */private int time;private MyThread(String name, int time) {this.name = name;this.time = time;}@Overridepublic void run() {try {// 休眠指定的時間Thread.sleep(this.time);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(this.name + "休眠" + this.time + "毫秒。");}}}

線程禮讓

Thread.yield 方法的調用聲明了當前線程已經(jīng)完成了生命周期中最重要的部分,可以切換給其它線程來執(zhí)行 。

該方法只是對線程調度器的一個建議,而且也只是建議具有相同優(yōu)先級的其它線程可以運行。

public class ThreadYieldDemo {public static void main(String[] args) {MyThread t = new MyThread();new Thread(t, "線程A").start();new Thread(t, "線程B").start();}static class MyThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 5; i++) {try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "運行,i = " + i);if (i == 2) {System.out.print("線程禮讓:");Thread.yield();}}}}
}

終止線程

Thread 中的 stop 方法有缺陷,已廢棄。

使用 Thread.stop 停止線程會導致它解鎖所有已鎖定的監(jiān)視器(由于未經(jīng)檢查的 ThreadDeath 異常會在堆棧中傳播,這是自然的結果)。 如果先前由這些監(jiān)視器保護的任何對象處于不一致狀態(tài),則損壞的對象將對其他線程可見,從而可能導致任意行為。

stop() 方法會真的殺死線程,不給線程喘息的機會,如果線程持有 ReentrantLock 鎖,被 stop() 的線程并不會自動調用 ReentrantLock 的 unlock() 去釋放鎖,那其他線程就再也沒機會獲得 ReentrantLock 鎖,這實在是太危險了。所以該方法就不建議使用了,類似的方法還有 suspend() 和 resume() 方法,這兩個方法同樣也都不建議使用了,所以這里也就不多介紹了。Thread.stop 的許多用法應由僅修改某些變量以指示目標線程應停止運行的代碼代替。 目標線程應定期檢查此變量,如果該變量指示要停止運行,則應按有序方式從其運行方法返回。如果目標線程等待很長時間(例如,在條件變量上),則應使用中斷方法來中斷等待。

當一個線程運行時,另一個線程可以直接通過 interrupt 方法中斷其運行狀態(tài)。

public class ThreadInterruptDemo {public static void main(String[] args) {MyThread mt = new MyThread(); // 實例化Runnable子類對象Thread t = new Thread(mt, "線程"); // 實例化Thread對象t.start(); // 啟動線程try {Thread.sleep(2000); // 線程休眠2秒} catch (InterruptedException e) {System.out.println("3、main線程休眠被終止");}t.interrupt(); // 中斷線程執(zhí)行}static class MyThread implements Runnable {@Overridepublic void run() {System.out.println("1、進入run()方法");try {Thread.sleep(10000); // 線程休眠10秒System.out.println("2、已經(jīng)完成了休眠");} catch (InterruptedException e) {System.out.println("3、MyThread線程休眠被終止");return; // 返回調用處}System.out.println("4、run()方法正常結束");}}
}

如果一個線程的 run 方法執(zhí)行一個無限循環(huán),并且沒有執(zhí)行 sleep 等會拋出 InterruptedException 的操作,那么調用線程的 interrupt 方法就無法使線程提前結束。

但是調用 interrupt 方法會設置線程的中斷標記,此時調用 interrupted 方法會返回 true。因此可以在循環(huán)體中使用 interrupted 方法來判斷線程是否處于中斷狀態(tài),從而提前結束線程。

安全地終止線程有兩種方法:

  • 定義 volatile 標志位,在 run 方法中使用標志位控制線程終止
  • 使用 interrupt 方法和 Thread.interrupted 方法配合使用來控制線程終止

【示例】使用 volatile 標志位控制線程終止

public class ThreadStopDemo2 {public static void main(String[] args) throws Exception {MyTask task = new MyTask();Thread thread = new Thread(task, "MyTask");thread.start();TimeUnit.MILLISECONDS.sleep(50);task.cancel();}private static class MyTask implements Runnable {private volatile boolean flag = true;private volatile long count = 0L;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " 線程啟動");while (flag) {System.out.println(count++);}System.out.println(Thread.currentThread().getName() + " 線程終止");}/*** 通過 volatile 標志位來控制線程終止*/public void cancel() {flag = false;}}}

【示例】使用 interrupt 方法和 Thread.interrupted 方法配合使用來控制線程終止

public class ThreadStopDemo3 {public static void main(String[] args) throws Exception {MyTask task = new MyTask();Thread thread = new Thread(task, "MyTask");thread.start();TimeUnit.MILLISECONDS.sleep(50);thread.interrupt();}private static class MyTask implements Runnable {private volatile long count = 0L;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + " 線程啟動");// 通過 Thread.interrupted 和 interrupt 配合來控制線程終止while (!Thread.interrupted()) {System.out.println(count++);}System.out.println(Thread.currentThread().getName() + " 線程終止");}}
}

守護線程

什么是守護線程?

  • 守護線程(Daemon Thread)是在后臺執(zhí)行并且不會阻止 JVM 終止的線程。當所有非守護線程結束時,程序也就終止,同時會殺死所有守護線程。
  • 與守護線程(Daemon Thread)相反的,叫用戶線程(User Thread),也就是非守護線程。

為什么需要守護線程?

  • 守護線程的優(yōu)先級比較低,用于為系統(tǒng)中的其它對象和線程提供服務。典型的應用就是垃圾回收器。

如何使用守護線程?

  • 可以使用 isDaemon 方法判斷線程是否為守護線程。
  • 可以使用 setDaemon 方法設置線程為守護線程。
    • 正在運行的用戶線程無法設置為守護線程,所以 setDaemon 必須在 thread.start 方法之前設置,否則會拋出 llegalThreadStateException 異常;
    • 一個守護線程創(chuàng)建的子線程依然是守護線程。
    • 不要認為所有的應用都可以分配給守護線程來進行服務,比如讀寫操作或者計算邏輯。
public class ThreadDaemonDemo {public static void main(String[] args) {Thread t = new Thread(new MyThread(), "線程");t.setDaemon(true); // 此線程在后臺運行System.out.println("線程 t 是否是守護進程:" + t.isDaemon());t.start(); // 啟動線程}static class MyThread implements Runnable {@Overridepublic void run() {while (true) {System.out.println(Thread.currentThread().getName() + "在運行。");}}}
}

參考閱讀:Java 中守護線程的總結

線程通信

當多個線程可以一起工作去解決某個問題時,如果某些部分必須在其它部分之前完成,那么就需要對線程進行協(xié)調。

wait/notify/notifyAll

  • wait - wait 會自動釋放當前線程占有的對象鎖,并請求操作系統(tǒng)掛起當前線程,讓線程從 Running 狀態(tài)轉入 Waiting 狀態(tài),等待 notify / notifyAll 來喚醒。如果沒有釋放鎖,那么其它線程就無法進入對象的同步方法或者同步控制塊中,那么就無法執(zhí)行 notify 或者 notifyAll 來喚醒掛起的線程,造成死鎖。
  • notify - 喚醒一個正在 Waiting 狀態(tài)的線程,并讓它拿到對象鎖,具體喚醒哪一個線程由 JVM 控制 。
  • notifyAll - 喚醒所有正在 Waiting 狀態(tài)的線程,接下來它們需要競爭對象鎖。

注意:

  • wait、notify、notifyAll 都是 Object 類中的方法,而非 Thread
  • wait、notifynotifyAll 只能用在 synchronized 方法或者 synchronized 代碼塊中使用,否則會在運行時拋出 IllegalMonitorStateException。

為什么 waitnotify、notifyAll 不定義在 Thread 中?為什么 wait、notify、notifyAll 要配合 synchronized 使用?

首先,需要了解幾個基本知識點:

  • 每一個 Java 對象都有一個與之對應的 監(jiān)視器(monitor)
  • 每一個監(jiān)視器里面都有一個 對象鎖 、一個 等待隊列、一個 同步隊列

了解了以上概念,我們回過頭來理解前面兩個問題。

為什么這幾個方法不定義在 Thread 中?

由于每個對象都擁有對象鎖,讓當前線程等待某個對象鎖,自然應該基于這個對象(Object)來操作,而非使用當前線程(Thread)來操作。因為當前線程可能會等待多個線程的鎖,如果基于線程(Thread)來操作,就非常復雜了。

為什么 wait、notify、notifyAll 要配合 synchronized 使用?

如果調用某個對象的 wait 方法,當前線程必須擁有這個對象的對象鎖,因此調用 wait 方法必須在 synchronized 方法和 synchronized 代碼塊中。

生產(chǎn)者、消費者模式是 waitnotify、notifyAll 的一個經(jīng)典使用案例:

public class ThreadWaitNotifyDemo02 {private static final int QUEUE_SIZE = 10;private static final PriorityQueue<Integer> queue = new PriorityQueue<>(QUEUE_SIZE);public static void main(String[] args) {new Producer("生產(chǎn)者A").start();new Producer("生產(chǎn)者B").start();new Consumer("消費者A").start();new Consumer("消費者B").start();}static class Consumer extends Thread {Consumer(String name) {super(name);}@Overridepublic void run() {while (true) {synchronized (queue) {while (queue.size() == 0) {try {System.out.println("隊列空,等待數(shù)據(jù)");queue.wait();} catch (InterruptedException e) {e.printStackTrace();queue.notifyAll();}}queue.poll(); // 每次移走隊首元素queue.notifyAll();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 從隊列取走一個元素,隊列當前有:" + queue.size() + "個元素");}}}}static class Producer extends Thread {Producer(String name) {super(name);}@Overridepublic void run() {while (true) {synchronized (queue) {while (queue.size() == QUEUE_SIZE) {try {System.out.println("隊列滿,等待有空余空間");queue.wait();} catch (InterruptedException e) {e.printStackTrace();queue.notifyAll();}}queue.offer(1); // 每次插入一個元素queue.notifyAll();try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 向隊列取中插入一個元素,隊列當前有:" + queue.size() + "個元素");}}}}
}

join

在線程操作中,可以使用 join 方法讓一個線程強制運行,線程強制運行期間,其他線程無法運行,必須等待此線程完成之后才可以繼續(xù)執(zhí)行。

public class ThreadJoinDemo {public static void main(String[] args) {MyThread mt = new MyThread(); // 實例化Runnable子類對象Thread t = new Thread(mt, "mythread"); // 實例化Thread對象t.start(); // 啟動線程for (int i = 0; i < 50; i++) {if (i > 10) {try {t.join(); // 線程強制運行} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("Main 線程運行 --> " + i);}}static class MyThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 50; i++) {System.out.println(Thread.currentThread().getName() + " 運行,i = " + i); // 取得當前線程的名字}}}
}

管道

管道輸入/輸出流和普通的文件輸入/輸出流或者網(wǎng)絡輸入/輸出流不同之處在于,它主要用于線程之間的數(shù)據(jù)傳輸,而傳輸?shù)拿浇闉閮?nèi)存。
管道輸入/輸出流主要包括了如下 4 種具體實現(xiàn):PipedOutputStream、PipedInputStream、PipedReaderPipedWriter,前兩種面向字節(jié),而后兩種面向字符。

public class Piped {public static void main(String[] args) throws Exception {PipedWriter out = new PipedWriter();PipedReader in = new PipedReader();// 將輸出流和輸入流進行連接,否則在使用時會拋出IOExceptionout.connect(in);Thread printThread = new Thread(new Print(in), "PrintThread");printThread.start();int receive = 0;try {while ((receive = System.in.read()) != -1) {out.write(receive);}} finally {out.close();}}static class Print implements Runnable {private PipedReader in;Print(PipedReader in) {this.in = in;}public void run() {int receive = 0;try {while ((receive = in.read()) != -1) {System.out.print((char) receive);}} catch (IOException e) {e.printStackTrace();}}}
}

線程生命周期

在這里插入圖片描述

java.lang.Thread.State 中定義了 6 種不同的線程狀態(tài),在給定的一個時刻,線程只能處于其中的一個狀態(tài)。

以下是各狀態(tài)的說明,以及狀態(tài)間的聯(lián)系:

  • 新建(New) - 尚未調用 start 方法的線程處于此狀態(tài)。此狀態(tài)意味著:創(chuàng)建的線程尚未啟動

  • 就緒(Runnable) - 已經(jīng)調用了 start 方法的線程處于此狀態(tài)。此狀態(tài)意味著:線程已經(jīng)在 JVM 中運行。但是在操作系統(tǒng)層面,它可能處于運行狀態(tài),也可能等待資源調度(例如處理器資源),資源調度完成就進入運行狀態(tài)。所以該狀態(tài)的可運行是指可以被運行,具體有沒有運行要看底層操作系統(tǒng)的資源調度。

  • 阻塞(Blocked) - 此狀態(tài)意味著:線程處于被阻塞狀態(tài)。表示線程在等待 synchronized 的隱式鎖(Monitor lock)。synchronized 修飾的方法、代碼塊同一時刻只允許一個線程執(zhí)行,其他線程只能等待,即處于阻塞狀態(tài)。當占用 synchronized 隱式鎖的線程釋放鎖,并且等待的線程獲得 synchronized 隱式鎖時,就又會從 BLOCKED 轉換到 RUNNABLE 狀態(tài)。

  • 等待(Waiting) - 此狀態(tài)意味著:線程無限期等待,直到被其他線程顯式地喚醒。 阻塞和等待的區(qū)別在于,阻塞是被動的,它是在等待獲取 synchronized 的隱式鎖。而等待是主動的,通過調用 Object.wait 等方法進入。

    進入方法退出方法
    沒有設置 Timeout 參數(shù)的 Object.wait 方法Object.notify / Object.notifyAll
    沒有設置 Timeout 參數(shù)的 Thread.join 方法被調用的線程執(zhí)行完畢
    LockSupport.park 方法(Java 并發(fā)包中的鎖,都是基于它實現(xiàn)的)LockSupport.unpark
  • 定時等待(Timed waiting) - 此狀態(tài)意味著:無需等待其它線程顯式地喚醒,在一定時間之后會被系統(tǒng)自動喚醒

    進入方法退出方法
    Thread.sleep 方法時間結束
    獲得 synchronized 隱式鎖的線程,調用設置了 Timeout 參數(shù)的 Object.wait 方法時間結束 / Object.notify / Object.notifyAll
    設置了 Timeout 參數(shù)的 Thread.join 方法時間結束 / 被調用的線程執(zhí)行完畢
    LockSupport.parkNanos 方法LockSupport.unpark
    LockSupport.parkUntil 方法LockSupport.unpark
  • 終止(Terminated) - 線程執(zhí)行完 run 方法,或者因異常退出了 run 方法。此狀態(tài)意味著:線程結束了生命周期。

線程常見問題

sleep、yield、join 方法有什么區(qū)別

  • yield 方法
    • yield 方法會 讓線程從 Running 狀態(tài)轉入 Runnable 狀態(tài)。
    • 當調用了 yield 方法后,只有與當前線程相同或更高優(yōu)先級的Runnable 狀態(tài)線程才會獲得執(zhí)行的機會。
  • sleep 方法
    • sleep 方法會 讓線程從 Running 狀態(tài)轉入 Waiting 狀態(tài)。
    • sleep 方法需要指定等待的時間,超過等待時間后,JVM 會將線程從 Waiting 狀態(tài)轉入 Runnable 狀態(tài)。
    • 當調用了 sleep 方法后,無論什么優(yōu)先級的線程都可以得到執(zhí)行機會。
    • sleep 方法不會釋放“鎖標志”,也就是說如果有 synchronized 同步塊,其他線程仍然不能訪問共享數(shù)據(jù)。
  • join
    • join 方法會 讓線程從 Running 狀態(tài)轉入 Waiting 狀態(tài)。
    • 當調用了 join 方法后,當前線程必須等待調用 join 方法的線程結束后才能繼續(xù)執(zhí)行

為什么 sleep 和 yield 方法是靜態(tài)的

Thread 類的 sleepyield 方法將處理 Running 狀態(tài)的線程。

所以在其他處于非 Running 狀態(tài)的線程上執(zhí)行這兩個方法是沒有意義的。這就是為什么這些方法是靜態(tài)的。它們可以在當前正在執(zhí)行的線程中工作,并避免程序員錯誤的認為可以在其他非運行線程調用這些方法。

Java 線程是否按照線程優(yōu)先級嚴格執(zhí)行

即使設置了線程的優(yōu)先級,也無法保證高優(yōu)先級的線程一定先執(zhí)行。

原因在于線程優(yōu)先級依賴于操作系統(tǒng)的支持,然而,不同的操作系統(tǒng)支持的線程優(yōu)先級并不相同,不能很好的和 Java 中線程優(yōu)先級一一對應。

一個線程兩次調用 start()方法會怎樣

Java 的線程是不允許啟動兩次的,第二次調用必然會拋出 IllegalThreadStateException,這是一種運行時異常,多次調用 start 被認為是編程錯誤。

startrun 方法有什么區(qū)別

  • run 方法是線程的執(zhí)行體。
  • start 方法會啟動線程,然后 JVM 會讓這個線程去執(zhí)行 run 方法。

可以直接調用 Thread 類的 run 方法么

  • 可以。但是如果直接調用 Threadrun 方法,它的行為就會和普通的方法一樣。
  • 為了在新的線程中執(zhí)行我們的代碼,必須使用 Threadstart 方法。

參考資料

  • 進程和線程關系及區(qū)別
  • sleep(),wait(),yield()和 join()方法的區(qū)別
  • Java 并發(fā)編程:線程間協(xié)作的兩種方式:wait、notify、notifyAll 和 Condition
  • Java 并發(fā)編程:Callable、Future 和 FutureTask
  • Java 中守護線程的總結
  • Java 并發(fā)
http://aloenet.com.cn/news/40435.html

相關文章:

  • 網(wǎng)站開發(fā)實用技術響應式網(wǎng)站模板的特點
  • 30天網(wǎng)站建設網(wǎng)站訪問量查詢工具
  • wordpress gallery類型seo網(wǎng)站優(yōu)化推薦
  • 新洲建設局網(wǎng)站如何實施網(wǎng)站推廣
  • 淘寶上做網(wǎng)站的信得過嗎東莞seo快速排名
  • 灰色行業(yè)老域名做網(wǎng)站不收錄小白如何學電商運營
  • 域名轉發(fā)網(wǎng)站朋友圈廣告30元 1000次
  • 男女直接做的視頻視頻網(wǎng)站蘇州seo怎么做
  • 關注公眾號功能開發(fā)seo優(yōu)化基礎教程pdf
  • 包工頭接活網(wǎng)站app軟件開發(fā)需要學什么
  • 淘寶u站怎么做網(wǎng)站的磁力蜘蛛
  • wordpress 信息查詢插件seo優(yōu)化技巧
  • 網(wǎng)站開發(fā)者不給源代碼怎么辦招商外包
  • eclipse網(wǎng)站開發(fā)實例域名批量注冊查詢
  • 建一個平臺網(wǎng)站需要多少錢網(wǎng)絡營銷包括的主要內(nèi)容有
  • 哈爾濱建站在線咨詢河北軟文搜索引擎推廣公司
  • 做網(wǎng)站好還是做安卓app好百度seo公司哪家好一點
  • 廣州網(wǎng)站建設 易點seo站點是什么意思
  • 杭州家具網(wǎng)站建設方案百度搜索引擎的特點
  • 源碼做網(wǎng)站教程網(wǎng)絡營銷服務公司
  • 有沒有電腦做兼職的網(wǎng)站嗎流量查詢網(wǎng)站
  • 珠海網(wǎng)站開發(fā)公司中國新聞網(wǎng)最新消息
  • 赤坎手機網(wǎng)站建設網(wǎng)絡項目怎么推廣
  • 宣傳做傳單的網(wǎng)站戶外廣告
  • 哪個網(wǎng)站買做房圖紙好鏈接推廣平臺
  • 做亞馬遜外國網(wǎng)站需要語言好嗎日本比分算1:1
  • 網(wǎng)站開發(fā)的研究思路seo經(jīng)理
  • html5笑話網(wǎng)站源碼上海seo網(wǎng)絡優(yōu)化
  • 直銷購物網(wǎng)站開發(fā)搜狗搜索引擎優(yōu)化
  • 泰安建設企業(yè)網(wǎng)站華與華營銷策劃公司