Java util concurrent及基本線程原理簡(jiǎn)介
一:什么是JUC
JUC就是java.util.concurrent下面的類包,專門用于多線程的開發(fā)。
二:進(jìn)程和線程的區(qū)別
進(jìn)程是可并發(fā)執(zhí)行的程序在某個(gè)數(shù)據(jù)集合上的一次計(jì)算活動(dòng),也是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位。
線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與 同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源。
并發(fā):多線程、 多個(gè)線程操作一個(gè)資源類,快速交替過(guò)程。
并行:多核多CPU;
線程的狀態(tài):(java底層源碼)
public enum State { NEW, // 新建線程 RUNNABLE, // 線程運(yùn)行 BLOCKED, // 線程阻塞 WAITING, // 等待 TIMED_WAITING, // 延時(shí)等待 TERMINATED; // 線程銷毀 }
三:wait和sleep的區(qū)別
1:類層面
wait ------object
sleep-------Thread 誰(shuí)調(diào)用誰(shuí)睡覺(jué)
2:是否釋放鎖層面
wait --------釋放鎖
sleep--------不釋放鎖
3:使用范圍層面
wait,notify,notifyall只能在同步方法中或者同步代碼塊中使用
sleep可以再任意的地方使用
4:異常
sleep必須捕獲異常
wait不需要捕獲異常
四:線程的幾種使用方式
1.優(yōu)先級(jí)
public final void setPriority(int newPriority)
更改線程的優(yōu)先級(jí)。
默認(rèn)為5,最小為1,最大為10
設(shè)置了優(yōu)先級(jí)別之后,級(jí)別高 并不是說(shuō)你一定被優(yōu)先調(diào)度,而是你的被優(yōu)先調(diào)度的概率高而已。
public class Test { public static void main(String[] args) { Tuzi tz=new Tuzi("兔子"); tz.setPriority(2); tz.start(); Wugui wg=new Wugui("烏龜"); wg.setPriority(8); wg.start(); } } public class Wugui extends Thread { @Override public void run() { for (int i = 1; i <=100; i++) { System.out.println("我是烏龜我在跑。。"+"----"+this.getName()+"---"+this.getPriority()); } } public Wugui(String name) { super(name); } }
2.線程強(qiáng)制運(yùn)行:join()
可以通過(guò)join()方法使得一個(gè)線程強(qiáng)制運(yùn)行,線程強(qiáng)制運(yùn)行期間,其他線程無(wú)法運(yùn)行,必須等待此線程完成之后,才可以繼續(xù)運(yùn)行。
public final void join() throws InterruptedException
等待該線程終止。
public final void join(long millis)throws InterruptedException
等待該線程終止的時(shí)間最長(zhǎng)為 millis 毫秒。超時(shí)為 0 意味著要一直等下去。
package Thread1; class MyThread implements Runnable{ // 實(shí)現(xiàn)Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<50;i++){ System.out.println(Thread.currentThread().getName() + "運(yùn)行,i = " + i) ; // 取得當(dāng)前線程的名字 } } }; public class demo1{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實(shí)例化Runnable子類對(duì)象 Thread t = new Thread(mt,"線程"); // 實(shí)例化Thread對(duì)象 t.start() ; // 啟動(dòng)線程 for(int i=0;i<50;i++){ if(i>10){ try{ t.join() ; // 線程強(qiáng)制運(yùn)行 }catch(InterruptedException e){} } System.out.println("Main線程運(yùn)行 --> " + i) ; } } };
3 線程的休眠(sleep)
在線程中允許一個(gè)線程進(jìn)行暫時(shí)的休眠,直接使用Thread.sleep()方法即可。
sleep定義格式:
public static void sleep(long milis,int nanos)
throws InterruptedException
首先,static,說(shuō)明可以由Thread類名稱調(diào)用,其次throws表示如果有異常要在調(diào)用此方法處處理異常。
所以sleep()方法要有InterruptedException 異常處理,而且sleep()調(diào)用方法通常為Thread.sleep(500) ;形式。
控制當(dāng)前線程休眠若干毫秒
* 1秒= 1000毫秒
* 1秒 = 1000 * 1000 * 1000納秒 1000000000
package Thread1; class MyThread implements Runnable{ // 實(shí)現(xiàn)Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<50;i++){ try{ Thread.sleep(500) ; // 線程休眠 }catch(InterruptedException e){} System.out.println(Thread.currentThread().getName() + "運(yùn)行,i = " + i) ; // 取得當(dāng)前線程的名字 } } }; public class demo1{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實(shí)例化Runnable子類對(duì)象 Thread t = new Thread(mt,"線程"); // 實(shí)例化Thread對(duì)象 t.start() ; // 啟動(dòng)線程 } };
4.線程的禮讓(yield)
yield()方法實(shí)現(xiàn)線程的禮讓。
package Thread1; class MyThread implements Runnable{ // 實(shí)現(xiàn)Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<5;i++){ try{ Thread.sleep(500) ; //休眠一下 }catch(Exception e){} System.out.println(Thread.currentThread().getName() + "運(yùn)行,i = " + i) ; // 取得當(dāng)前線程的名字 if(i==2){ System.out.print("線程禮讓:") ; Thread.currentThread().yield() ; // 首先獲取當(dāng)前線程,然后線程禮讓 } } } }; public class demo1{ public static void main(String args[]){ MyThread my = new MyThread() ; // 實(shí)例化MyThread對(duì)象 Thread t1 = new Thread(my,"線程A") ; Thread t2 = new Thread(my,"線程B") ; t1.start() ; t2.start() ; } };
5.判斷線程是否在執(zhí)行:isAlive
class MyThread implements Runnable{ // 實(shí)現(xiàn)Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<3;i++){ System.out.println(Thread.currentThread().getName() + "運(yùn)行,i = " + i) ; // 取得當(dāng)前線程的名字 } } }; public class ThreadAliveDemo{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實(shí)例化Runnable子類對(duì)象 Thread t = new Thread(mt,"線程"); // 實(shí)例化Thread對(duì)象 System.out.println("線程開始執(zhí)行之前 --> " + t.isAlive()) ; // 判斷是否啟動(dòng) t.start() ; // 啟動(dòng)線程 System.out.println("線程開始執(zhí)行之后 --> " + t.isAlive()) ; // 判斷是否啟動(dòng) for(int i=0;i<3;i++){ System.out.println(" main運(yùn)行 --> " + i) ; } // 以下的輸出結(jié)果不確定 System.out.println("代碼執(zhí)行之后 --> " + t.isAlive()) ; // 判斷是否啟動(dòng) } };
6.當(dāng)前線程:CurrentThread()
程序可以通過(guò)currentThread()方法取得當(dāng)前正在運(yùn)行的線程對(duì)象,
class MyThread implements Runnable{ // 實(shí)現(xiàn)Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<3;i++){ System.out.println(Thread.currentThread().getName() + "運(yùn)行,i = " + i) ; // 取得當(dāng)前線程的名字 } } }; public class CurrentThreadDemo{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實(shí)例化Runnable子類對(duì)象 new Thread(mt,"線程").start() ; // 啟動(dòng)線程 mt.run() ; // 直接調(diào)用run()方法 } };
7.線程名稱
1,在Thread類中可以通過(guò)getName()方法取得線程名稱,通過(guò)setName()設(shè)置線程名稱。
2,線程的名稱一般在啟動(dòng)線程前設(shè)置,但也允許為運(yùn)行的線程設(shè)置名稱,允許兩個(gè)Thread對(duì)象有相同名稱,但是應(yīng)該避免。
3,如果程序沒(méi)有為線程指定名稱,系統(tǒng)會(huì)自動(dòng)為線程設(shè)置名稱。
class MyThread implements Runnable{ // 實(shí)現(xiàn)Runnable接口 public void run(){ // 覆寫run()方法 for(int i=0;i<3;i++){ System.out.println(Thread.currentThread().getName() + "運(yùn)行,i = " + i) ; // 取得當(dāng)前線程的名字 } } }; public class ThreadNameDemo{ public static void main(String args[]){ MyThread mt = new MyThread() ; // 實(shí)例化Runnable子類對(duì)象 new Thread(mt).start() ; // 系統(tǒng)自動(dòng)設(shè)置線程名稱 new Thread(mt,"線程-A").start() ; // 手工設(shè)置線程名稱 new Thread(mt,"線程-B").start() ; // 手工設(shè)置線程名稱 new Thread(mt).start() ; // 系統(tǒng)自動(dòng)設(shè)置線程名稱 new Thread(mt).start() ; // 系統(tǒng)自動(dòng)設(shè)置線程名稱 } };
五:幾種方法的比較
- Thread.sleep(long millis),一定是當(dāng)前線程調(diào)用此方法,當(dāng)前線程進(jìn)入阻塞,但不釋放對(duì)象鎖,millis后線程自動(dòng)蘇醒進(jìn)入可運(yùn)行狀態(tài)。作用:給其它線程執(zhí)行機(jī)會(huì)的最佳方式。
- Thread.yield(),一定是當(dāng)前線程調(diào)用此方法,當(dāng)前線程放棄獲取的cpu時(shí)間片,由運(yùn)行狀態(tài)變會(huì)可運(yùn)行狀態(tài),讓OS再次選擇線程。作用:讓相同優(yōu)先級(jí)的線程輪流執(zhí)行,但并不保證一定會(huì)輪流執(zhí)行。實(shí)際中無(wú)法保證yield()達(dá)到讓步目的,因?yàn)樽尣降木€程還有可能被線程調(diào)度程序再次選中。Thread.yield()不會(huì)導(dǎo)致阻塞。
- t.join()/t.join(long millis),當(dāng)前線程里調(diào)用其它線程1的join方法,當(dāng)前線程阻塞,但不釋放對(duì)象鎖,直到線程1執(zhí)行完畢或者millis時(shí)間到,當(dāng)前線程進(jìn)入可運(yùn)行狀態(tài)。
- obj.wait(),當(dāng)前線程調(diào)用對(duì)象的wait()方法,當(dāng)前線程釋放對(duì)象鎖,進(jìn)入等待隊(duì)列。依靠notify()/notifyAll()喚醒或者wait(long timeout)timeout時(shí)間到自動(dòng)喚醒。
- obj.notify()喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程,選擇是任意性的。notifyAll()喚醒在此對(duì)象監(jiān)視器上等待的所有線程。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
mybatis之嵌套查詢和嵌套結(jié)果有哪些區(qū)別
這篇文章主要介紹了mybatis之嵌套查詢和嵌套結(jié)果有哪些區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Java之Error與Exception的區(qū)別案例詳解
這篇文章主要介紹了Java之Error與Exception的區(qū)別案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09Spring boot 默認(rèn)靜態(tài)資源路徑與手動(dòng)配置訪問(wèn)路徑的方法
這篇文章主要介紹了Spring boot 默認(rèn)靜態(tài)資源路徑與手動(dòng)配置訪問(wèn)路徑的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-05-05Java 網(wǎng)絡(luò)爬蟲基礎(chǔ)知識(shí)入門解析
這篇文章主要介紹了Java 網(wǎng)絡(luò)爬蟲基礎(chǔ)知識(shí)入門解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10SpringBoot+Redis實(shí)現(xiàn)接口防刷的示例代碼
在實(shí)際開發(fā)中,會(huì)出現(xiàn)用戶多次點(diǎn)擊發(fā)送請(qǐng)求,本文主要介紹了SpringBoot+Redis實(shí)現(xiàn)接口防刷的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01使用httpclient實(shí)現(xiàn)免費(fèi)的google翻譯api
這篇文章主要介紹了使用httpclient實(shí)現(xiàn)免費(fèi)的google翻譯api的方法,大家參考使用吧2014-01-01