摘要:在程序開發(fā)中一定遇到并發(fā)編程的場景雖然我們大部分時間并不直接使用但是是多線程的基礎(chǔ)面試中也會總是被問到與線程有關(guān)的問題那么線程都有哪些知識呢最近在研究線程的源碼的時候也總結(jié)了關(guān)于線程一些基本知識線程是什么線程是輕量級的進(jìn)程是操作系統(tǒng)調(diào)度任務(wù)
在程序開發(fā)中, 一定遇到并發(fā)編程的場景, 雖然我們大部分時間并不直接使用Thread, 但是Thread是多線程的基礎(chǔ), 面試中也會總是被問到與線程有關(guān)的問題; 那么線程都有哪些知識呢? 最近在研究線程的源碼的時候也總結(jié)了關(guān)于線程一些基本知識;線程是什么
線程是輕量級的進(jìn)程, 是操作系統(tǒng)調(diào)度任務(wù)到CPU的最小單元;
多線程編程的優(yōu)點(diǎn)1、多線程編程能夠最大程度的利用多核設(shè)備上面的CPU資源, 保證任務(wù)處理的足夠快, 及時響應(yīng)客戶端的額請求
2、線程的創(chuàng)建的代價比創(chuàng)建進(jìn)程的代價小很多, 同時多線程的上下文切換也更快; 《操作系統(tǒng)概念 第六版》 在Solaris 2上面, 創(chuàng)建進(jìn)程比創(chuàng)建線程慢30倍, 而進(jìn)程的上下文切換比線程的上下文切換慢5倍;
Java中線程的狀態(tài)有哪些查看java.lang.Thread的源碼有如下代碼:
public enum State { /** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ RUNNABLE, /** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: *
A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called Object.wait() * on an object is waiting for another thread to call * Object.notify() or Object.notifyAll() on * that object. A thread that has called Thread.join() * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: *
1、NEW: 線程還沒有啟動的時候, 狀態(tài)就是NEW 即 新建狀態(tài)
2、RUNNABLE: 當(dāng)一個線程處于運(yùn)行中或者等待CPU調(diào)度的時候, 狀態(tài)就是 RUNNABLE狀態(tài); 有些地方也稱為 就緒狀態(tài)
3、BLOCKED: 當(dāng)一個線程在等待別的線程釋放鎖資源的時候, 狀態(tài)就是BLOCKED, 或者在該線程獲取到鎖之后, 在同步代碼塊里面調(diào)用了Wait方法, 這時候釋放鎖, 在獲取到其他線程的notify或者notifyAll通知之后, 重新進(jìn)入 同步代碼塊這段時間 該線程也是BLOCKED狀態(tài)的;
4、WAITING: 當(dāng)正在運(yùn)行的線程調(diào)用了Object.wait()方法 或者 Thread.join()方法 或者 LockSupport.park()方法之后, 會進(jìn)入到WAITING狀態(tài)
5、TIMED_WAITING: 當(dāng)正在運(yùn)行的線程調(diào)用Object.wait(n) 或者 Thread.join(n) 或者 LockSupport.parkUntil(blocker, n) 會進(jìn)入到 TIMED_WAITING 狀態(tài)
6、TERMINATED: 當(dāng)線程結(jié)束后, 會進(jìn)入到 TERMINATED 狀態(tài).
狀態(tài)轉(zhuǎn)換如下, 該圖中比Java的狀態(tài)多了一個RUNNING狀態(tài), 來區(qū)別 線程的就緒狀態(tài) 與 運(yùn)行狀態(tài) 更加方便讀者理解;
線程狀態(tài)轉(zhuǎn)換 線程狀態(tài)轉(zhuǎn)換之NEW下面來看一下線程的狀態(tài)轉(zhuǎn)換用Java怎么實(shí)現(xiàn):
如上面所述: 剛剛創(chuàng)建的線程處于NEW狀態(tài), 那么我們可以通過如下代碼打印其狀態(tài):
Thread thread = new Thread(new Runnable() { public void run() { } }); System.out.println(thread.getState());線程狀態(tài)轉(zhuǎn)換之RUNNABLE
那么線程如何進(jìn)入到RUNNABLE狀態(tài)呢? 調(diào)用Thread的start方法即可; 我們在Runnable的實(shí)現(xiàn)里面增加對于當(dāng)前線程狀態(tài)的打印即可:
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { public void run() { System.out.println("線程進(jìn)入:" + Thread.currentThread().getState()); } }); System.out.println(thread.getState()); thread.start(); }線程狀態(tài)轉(zhuǎn)換之TIMED_WAITING
那么線程怎么進(jìn)入到TIMED_WAITING狀態(tài)呢? 通過調(diào)用 sleep(n) join(n) 或者 wait(n)都可以進(jìn)入到TIMED_WAITING狀態(tài):
調(diào)用Thread.sleep()
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { public void run() { System.out.println("線程進(jìn)入:" + Thread.currentThread().getState()); try { Thread.sleep(1000 * 60); } catch (InterruptedException e) { e.printStackTrace(); } } }); System.out.println(thread.getState()); thread.start(); }
調(diào)用obj.wait(time)
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("線程進(jìn)入:" + Thread.currentThread().getState()); try { Client.class.wait(60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); System.out.println(thread.getState()); thread.start(); }
上圖中表示: 在Client.class上面等待; 等待其他對象調(diào)用Client.class.notify()方法或者等待時間到期.
調(diào)用thread.join(time)
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("線程進(jìn)入:" + Thread.currentThread().getState()); try { Client.class.wait(60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Client.class對象上等待超時"); } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { thread.join(50 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1結(jié)束"); } } }); thread2.start(); }
表示 第二個線程在等待第一個線程執(zhí)行完成或者超時;
線程狀態(tài)轉(zhuǎn)換之WAITING如果想要一個線程進(jìn)入到WAITING狀態(tài), 那么只需要跟上面步驟一樣, Thread.sleep()除外, 但是調(diào)用的時候不要傳超時時間即可;
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("線程進(jìn)入:" + Thread.currentThread().getState()); try { Client.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("被其他線程調(diào)用Client.class.notify()喚醒"); } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { thread.join(50 * 1000); Client.class.notify(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1結(jié)束"); } } }); thread2.start(); }
只要是沒有時間的等待都會處于WAITING狀態(tài), 比如把上面代碼修改一下, 換成join()也可以讓線程處于 WAITING狀態(tài):
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("線程進(jìn)入:" + Thread.currentThread().getState()); try { Client.class.wait(50 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("被其他線程調(diào)用Client.class.notify()喚醒"); } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { System.out.println("即將進(jìn)入等待線程1完成的狀態(tài)"); thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1結(jié)束"); } } }); thread2.start(); }
如上代碼表示線程2會在線程1執(zhí)行結(jié)束之后再結(jié)束, 所以線程2就會進(jìn)入到WATIING狀態(tài)
線程狀態(tài)轉(zhuǎn)換之BLOCKED上面已經(jīng)看到, 通過調(diào)用線程的函數(shù)就可以控制線程的狀態(tài), 那么如何進(jìn)入到BLOCKED狀態(tài)呢?進(jìn)入到BLOCKED狀態(tài), 按照上面的轉(zhuǎn)換圖 可以翻譯為 多個線程出現(xiàn)竟態(tài)的時候, 其他線程會進(jìn)入BLOCKED狀態(tài), 只有一個線程會在RUNNABLE狀態(tài),比如如下代碼:
public static void main(String[] args) { final Thread thread = new Thread(new Runnable() { public void run() { synchronized (Client.class) { System.out.println("線程進(jìn)入:" + Thread.currentThread().getState()); try { Thread.sleep(1000 * 50); } catch (InterruptedException e) { e.printStackTrace(); } } } }); System.out.println(thread.getState()); thread.start(); Thread thread2 = new Thread(new Runnable() { public void run() { synchronized (Client.class) { try { System.out.println("即將進(jìn)入等待線程1完成的狀態(tài)"); thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1結(jié)束"); } } }); thread2.start(); }
當(dāng)然, 對于A線程調(diào)用了Object.class.wait()方法釋放鎖之后, 最后被其他線程調(diào)用Object.class.notify() A線程再次進(jìn)入RUNNABLE之前的狀態(tài)就是 BLOCKED;
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/73607.html
摘要:開發(fā)中不可避免用到多線程情況,比如中常見的都是運(yùn)用到多線程,多線程的根本目的是為了更快的執(zhí)行。其他常用到的多線程比如設(shè)計到大量操作用多線程可明顯提升效率。中最基礎(chǔ)的并發(fā)類就是是一個接口,只要實(shí)現(xiàn)實(shí)現(xiàn),重寫方法就可以實(shí)現(xiàn)多線程操作。 java開發(fā)中不可避免用到多線程情況,比如web中常見的Servlet、Struts2都是運(yùn)用到多線程,多線程的根本目的是為了更快的執(zhí)行。其他常用到的多線程...
摘要:可以用代替可以用代替定義的對象的值是不可變的今天就先到這里,大家可以看看這些內(nèi)容的拓展記得點(diǎn)關(guān)注看更新,謝謝閱讀 前言 java高并發(fā)第二篇講的是java線程的基礎(chǔ)依舊不多說廢話 線程和進(jìn)程 進(jìn)程是操作系統(tǒng)運(yùn)行的基礎(chǔ),是一個程序運(yùn)行的實(shí)體,windows上打開任務(wù)管理器就能看到進(jìn)程線程是輕量級的進(jìn)程,是程序執(zhí)行的最小單位,是在進(jìn)程這個容器下進(jìn)行的 線程基本操作 新建一個線程類有兩種方式...
摘要:基本在項(xiàng)目開發(fā)中基本不會用到但是面試官是比較喜歡問這類問題的所以還是有必要了解一下該類的功能與原理的是什么是一個將在多線程中為每一個線程創(chuàng)建單獨(dú)的變量副本的類當(dāng)使用來維護(hù)變量時會為每個線程創(chuàng)建單獨(dú)的變量副本避免因多線程操作共享變量而導(dǎo)致的數(shù) ThreadLocal基本在項(xiàng)目開發(fā)中基本不會用到, 但是面試官是比較喜歡問這類問題的;所以還是有必要了解一下該類的功能與原理的. Thread...
摘要:線程間通信其實(shí)就是多個線程操作同一個資源,但動作不同。同步前提是多線程。將該線程載入線程池,等待喚醒。該方法拋出異常,故需要配合使用隨機(jī)喚醒線程池中一線程。線程為了檢測死鎖,它需要遞進(jìn)地檢測所有被請求的鎖。 線程間通信 其實(shí)就是多個線程操作同一個資源,但動作不同。示例:在某個數(shù)據(jù)庫中,Input輸入人的姓名,性別,Output輸出,兩個線程同時作用。思考:1.明確哪些代碼是多線程操作的...
摘要:常用于臨時加入線程。重載形式等待被的線程執(zhí)行完成。當(dāng)正在運(yùn)行的線程都是守護(hù)線程時,虛擬機(jī)退出。為線程對象設(shè)置優(yōu)先級類定義了三個靜態(tài)常量停止線程釋放執(zhí)行線程的執(zhí)行權(quán),讓重新調(diào)度一次,但仍有可能回到該線程。 join()線程當(dāng)A線程執(zhí)行到了B線程的join()方法時,A線程就會等待B線程執(zhí)行完,A線程才會執(zhí)行。join()常用于臨時加入線程。重載形式:join():等待被join的線程執(zhí)行...
閱讀 2132·2021-11-19 09:58
閱讀 1719·2021-11-15 11:36
閱讀 2879·2019-08-30 15:54
閱讀 3399·2019-08-29 15:07
閱讀 2771·2019-08-26 11:47
閱讀 2825·2019-08-26 10:11
閱讀 2511·2019-08-23 18:22
閱讀 2759·2019-08-23 17:58