W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎勵
1.什么是進(jìn)程
- 程序是指令和數(shù)據(jù)的有序的集合,其本身沒有任何運(yùn)行的含義,是一個(gè)靜態(tài)的概念
- 進(jìn)程是一個(gè)具有一定獨(dú)立功能的程序,一個(gè)實(shí)體
- 幾乎所有的操作系統(tǒng)都支持同時(shí)運(yùn)行多個(gè)任務(wù),一個(gè)任務(wù)通常就是一個(gè)程序,每個(gè)運(yùn)行中的程序就是一個(gè)進(jìn)程
- 當(dāng)一個(gè)程序運(yùn)行時(shí),內(nèi)部可能包含了多個(gè)順序執(zhí)行流,每個(gè)順序執(zhí)行流就是一個(gè)線程
2.進(jìn)程的狀態(tài): 進(jìn)程執(zhí)行時(shí)的間斷性,決定了進(jìn)程可能具有多種狀態(tài),事實(shí)上,運(yùn)行中的進(jìn)程具有
- 以下三種基本狀態(tài):
- 1.就緒狀態(tài)(Ready)
- 2.運(yùn)行狀態(tài)(Running)
- 3.阻塞狀態(tài)(Blocked)
3.線程
- 線程實(shí)際上是進(jìn)程基礎(chǔ)之上的進(jìn)一步劃分,一個(gè)進(jìn)程啟動之后,里面的若干程序,又可以劃分成若干個(gè)線程
- 線程:是進(jìn)程中的一個(gè)執(zhí)行路徑,共享一個(gè)內(nèi)存空間,線程之間可以自由切換
- 并發(fā)執(zhí)行,一個(gè)進(jìn)程最少有一個(gè)線程(單線程程序)
4.線程實(shí)現(xiàn)的兩種方式
- 在java中如果想要實(shí)現(xiàn)多線程操作,兩種實(shí)現(xiàn)方法
- 1.一種是繼承Thrcad類
- 2.另一種是實(shí)現(xiàn)Runnable接口
5.多線程編程的優(yōu)勢
- 進(jìn)程間不能共享內(nèi)存,但線程之間共享內(nèi)存非常容易
- 系統(tǒng)創(chuàng)建進(jìn)程需要為該進(jìn)程重新分配系統(tǒng)資源,但創(chuàng)建線程則代價(jià)小得多,因此使用多線程來實(shí)現(xiàn)多任務(wù)并發(fā)比多進(jìn)程的效率高
- Java語言內(nèi)置的多線程功能支持,而不是單純地作為底層操作系統(tǒng)的調(diào)度方式,從而簡化了Java的多線程編程
(1)定義Thread類的子類,并重寫該類的run方法,該run方法的方法體就是代表了線程需要完成的任務(wù)
因此,我們經(jīng)常把run方法稱為線程執(zhí)行體
(2)創(chuàng)建Thread子類的實(shí)例,即創(chuàng)建了線程對象
(3)調(diào)用線程對象的start方法來啟動該線程
(4)join線程:Thread提供了讓一個(gè)線程等待另一個(gè)線程完成的方法:join() 方法
當(dāng)在某個(gè)程序執(zhí)行流中調(diào)用其他線程的join()方法時(shí),調(diào)用線程將被阻塞,直到被join方法加入的join線程完成為止
join()方法通常由使用線程的程序調(diào)用,以將大問題劃分成許多小問題,每個(gè)小問題分配一個(gè)線程。當(dāng)所有的小問題都得到處理后,再調(diào)用主線程來進(jìn)一步操作
(1)定義Runnable接口的實(shí)現(xiàn)類,并重寫該接口的run方法,該run方法的方法體同樣是該線程的線程執(zhí)行體
(2)創(chuàng)建Runnable實(shí)現(xiàn)類的實(shí)例,并以此實(shí)例作為Thread的target來創(chuàng)建Thread對象,該Thread對象才是真正的線程對象
(3)調(diào)用線程對象的start方法來啟動該線程
如果我們需要讓當(dāng)前正在執(zhí)行的線程暫停一段時(shí)間,并進(jìn)入阻塞狀態(tài)
則可以通過調(diào)用Thread類的靜態(tài)sleep方法,sleep方法有兩種重載的形式:
- static void sleep(long millis):讓當(dāng)前正在執(zhí)行的線程暫停millis毫秒,并進(jìn)入阻塞狀態(tài),該方法受到系統(tǒng)計(jì)時(shí)器和線程調(diào)度器的精度和準(zhǔn)確度的影響
- static void sleep(long millis, int nanos):讓當(dāng)前正在執(zhí)行的線程暫停millis毫秒加nanos毫微妙,并進(jìn)入阻塞狀態(tài),該方法受到系統(tǒng)計(jì)時(shí)器和線程調(diào)度器的精度和準(zhǔn)確度的影響
采用實(shí)現(xiàn)Runnable接口方式的多線程:
- 線程類只是實(shí)現(xiàn)了Runnable接口,還可以可以繼承其他類
- 在這種方式下,可以多個(gè)線程共享同一個(gè)target對象,所以非常適合多個(gè)相同線程來處理同一份資源的情況
- 從而可以將CPU,代碼和數(shù)據(jù)分開,形成清晰的模型,較好地體現(xiàn)了面向?qū)ο蟮乃枷?
- 劣勢:編程稍稍復(fù)雜,如果需要訪問當(dāng)前線程,必須使用Thread.currentThread()方法
采用繼承Thread類方式的多線程:
- 劣勢:因?yàn)榫€程類已經(jīng)繼承了Thread類,所以不能再繼承其他父類
- 優(yōu)勢:編寫簡單,如果需要訪問當(dāng)前線程,無需使用Thread.currentThread()方法,直接使用this即可獲得當(dāng)前線程
線程聲明周期:
- 就緒狀態(tài)
- 執(zhí)行狀態(tài)
- 阻塞狀態(tài)
多條線程并發(fā)修改共享資源就容易引發(fā)線程安全問題
使用同步解決多線程共享數(shù)據(jù)出現(xiàn)安全問題
多個(gè)線程有可能同時(shí)處理同一個(gè)資源
線程同步就是指多個(gè)線程在同一個(gè)時(shí)間段內(nèi)只能有一個(gè)線程執(zhí)行指定代碼
其他線程等待此線程完成之后才可以繼續(xù)執(zhí)行
同步代碼塊synchronized(要同步對象){要同步的操作}
同步方法public synchronized void method(){要同步的操作}
同步代碼會帶來性能降低的問題,提高數(shù)據(jù)的安全性,犧牲性能來保證安全
同步代碼塊
Java的多線程支持引入了同步監(jiān)視器來解決這個(gè)問題,使用同步監(jiān)視器的通用方法就是同步代碼塊
synchronized后括號里的obj就是同步監(jiān)視器,上面代碼的含義是:線程開始執(zhí)行同步代碼塊之前,必須先獲得對同步監(jiān)視器的鎖定
同步方法
Java的多線程安全支持還提供了同步方法,同步方法就是使用synchronized關(guān)鍵字來修飾某個(gè)方法,則該方法成為同步方法
對于同步方法而言,無需顯式指定同步監(jiān)視器,同步方法的同步監(jiān)視器是this,也就是該對象本身
線程死鎖
過多的同步有可能死鎖,死鎖的操作一般是在程序運(yùn)行的時(shí)候才有可能出現(xiàn)
多線程中要進(jìn)行資源的共享,就需要同步,但同步過多,就可能造成死鎖
<br> package cn.jeep; <br> //繼承Thread類 <br> public class XianChengDemo extends Thread{ <br> private int i;//私有成員屬性 <br> //重寫run方法,run方法的方法體就是線程執(zhí)行體 <br> public void run(){ <br> for(;i<100;i++){ <br> //當(dāng)線程類繼承Thread類時(shí),直接使用this.及格獲取當(dāng)前線程 <br> //Thread對象的getNname()返回當(dāng)前線程名字 <br> //因此可以直接調(diào)用getName方法返回當(dāng)前線程名字 <br> System.out.println(getName()+" "+i); <br> } <br> } <br> //主方法入口 <br> public static void main(String[] args) { <br> for(int i=0;i<100;i++){ <br> //調(diào)用Thread的currenTread方法獲取當(dāng)前線程 <br> System.out.println(Thread.currentThread().getName()+" "+i); <br> if(i == 20){ <br> //創(chuàng)建并啟動第一個(gè)線程 <br> new XianChengDemo().start(); <br> //創(chuàng)建并啟動第二個(gè)線程 <br> new XianChengDemo().start(); <br> } <br> } <br> } <br> } <br> ``` <br>``` <br> package cn.runnable; <br> //聲明一個(gè)類 <br> public class RunnableDenmo implements Runnable{ <br> private int i;//私有屬性 <br> //重寫run方法 <br> public void run(){ <br> for(;i<100;i++){ <br> //當(dāng)線程類實(shí)現(xiàn)Runnable接口時(shí) <br> //如果想獲取當(dāng)前線程,只能用Thread.currentTread()方法 <br> System.out.println(Thread.currentThread().getName()+" "+i); <br> } <br> } <br> //主方法 <br> public static void main(String[] args) { <br> for(int i=0;i<100;i++){ <br> System.out.println(Thread.currentThread().getName()+" "+i); <br> if(i == 20){ <br> RunnableDenmo st = new RunnableDenmo(); <br> //通過new Thread(target,name)方法創(chuàng)建新線程 <br> new Thread(st,"新線程1").start(); <br> new Thread(st,"新線程2").start(); <br> } <br> } <br> } <br> } <br>``` <br>``` <br> package cn.callable; <br> import java.util.concurrent.Callable; <br> import java.util.concurrent.FutureTask; <br> public class CallableDemo { <br> public static void main(String[] args) { <br> //創(chuàng)建Callable對象 <br> @SuppressWarnings("unused") <br> CallableDemo cl = new CallableDemo(); <br> //先使用Lambda表達(dá)式創(chuàng)建Callable<Integer&對象 <br> //使用FutureTask來包裝Callable對象 <br> FutureTask<Integer& task = new FutureTask<Integer&((Callable<Integer&)()-&{ <br> int i = 0; <br> for(;i<100;i++){ <br> System.out.println(Thread.currentThread().getName()+"的循環(huán)變量的i的值:"+i); <br> } <br> //call()方法可以有返回值 <br> return i; <br> }); <br> for(int i=0;i<100;i++){ <br> if(i==20){ <br> //實(shí)質(zhì)還是以Callable對象來創(chuàng)建并啟動線程 <br> new Thread(task,"有返回值得線程").start(); <br> } <br> } <br> try{ <br> //獲取線程返回值 <br> System.out.println("子線程的返回值:"+task.get()); <br> }catch(Exception ex){ <br> ex.printStackTrace(); <br> } <br> } <br> } <br>```
<br> package cn.tongbu; <br> public class TB { <br> public static void main(String[] args) { <br> TbDemo tb = new TbDemo(); <br> Thread t1 = new Thread(tb,"小明"); <br> Thread t2 = new Thread(tb,"小白"); <br> Thread t3 = new Thread(tb,"小紅"); <br> Thread t4 = new Thread(tb,"小黑"); <br> Thread t5 = new Thread(tb,"小華"); <br> t1.start(); <br> t2.start(); <br> t3.start(); <br> t4.start(); <br> t5.start(); <br> } <br> } <br> class TbDemo implements Runnable{ <br> Object obj = new Object();//同步得標(biāo)記 <br> @Override <br> public void run() { <br> //線程同步代碼塊 <br> //synchronized(obj){ <br> //} <br> say();//調(diào)用同步方法 <br> } <br> /** <br> * 同步方法 <br> */ <br> public synchronized void say(){ <br> System.out.println(Thread.currentThread().getName()+"正在通話中...."); <br> try { <br> Thread.sleep(2000);//2秒 <br> } catch (InterruptedException e) { <br> e.printStackTrace(); <br> } <br> System.out.println(Thread.currentThread().getName()+"通話結(jié)束!"); <br> } <br> } <br> ```
<br> package cn.sisuo; <br> public class SiSuoDemo { <br> public static void main(String[] args) { <br> new Ss(); <br> } <br> } <br> //警 <br> class XingJing{ <br> //同步方法 <br> public synchronized void say(FeiTu f){ <br> System.out.println("警方說先放人質(zhì),在實(shí)行抓捕"); <br> f.dos(); <br> } <br> public synchronized void dos(){ <br> System.out.println("同意匪徒要求,在實(shí)行抓捕"); <br> } <br> } <br> //匪徒 <br> class FeiTu{ <br> //同步方法 <br> public synchronized void say(XingJing x){ <br> System.out.println("匪徒說先找一輛車,在放人質(zhì)"); <br> x.dos(); <br> } <br> public synchronized void dos(){ <br> System.out.println("先找一輛車,再放人質(zhì)"); <br> } <br> } <br> /** <br> * 死鎖線程 <br> * @author JEEP-711 <br> * <br> */ <br> class Ss implements Runnable{ <br> XingJing xj = new XingJing(); <br> FeiTu ft = new FeiTu(); <br> //模擬線程死鎖構(gòu)造方法 <br> public Ss(){ <br> new Thread(this).start();//為了快速實(shí)現(xiàn) <br> ft.say(xj); <br> } <br> @Override <br> public void run() { <br> xj.say(ft); <br> } <br> } <br> ```
<br> package cn.chinabank;//中國銀行包 <br> //聲明一個(gè)賬戶類 <br> public class Account { <br> private String name;//私有屬性-姓名 <br> private double number=0.0;//私有屬性-余額 <br> //構(gòu)造方法并傳值 <br> public Account(String name,double number){ <br> this.name = name;//當(dāng)前姓名 <br> this.number = number;//當(dāng)前金額 <br> } <br> //取得getName方法 <br> public String getName() { <br> return name; <br> } <br> //設(shè)置setName方法 <br> public void setName(String name) { <br> this.name = name; <br> } <br> //取得getNumber方法 <br> public double getNumber() { <br> return number; <br> } <br> //設(shè)置setNumber方法 <br> public void setNumber(double number) { <br> this.number = number; <br> } <br> } <br> ``` <br> ``` <br> package cn.chinabank;//中國銀行包 <br> import java.util.Scanner; <br> //聲明一個(gè)中國銀行類 <br> public class ChinaBank { <br> //定義主方法 <br> public static void main(String[] args) { <br> @SuppressWarnings("resource") <br> Scanner sc = new Scanner(System.in);//接收控制臺鍵盤輸入 <br> System.out.println("----------------------"); <br> System.out.println("----歡迎您進(jìn)入中國銀行-----"); <br> System.out.println("---請選擇您需要辦理的業(yè)務(wù)---"); <br> System.out.println("1.存款"+"\t"+" 2.取款"+"\t"+"3.退出"); <br> System.out.println("----------------------"); <br> int sr = sc.nextInt();//接收一個(gè)數(shù) <br> //接收用戶輸入 <br> switch(sr){ <br> //輸入1則進(jìn)入存款功能 <br> case 1: <br> System.out.println("請您輸入存款金額:");//提示用戶存款金額 <br> double number = sc.nextDouble();//接收用戶輸入金額 <br> @SuppressWarnings("unused") <br> Account account1 = new Account("asdd",number);//創(chuàng)建Accound對象 <br> System.out.println("請您將鈔票疊整齊后放入存鈔口..");//提示用戶將鈔票放入存鈔口 <br> try{ <br> Thread.sleep(2000);//模仿現(xiàn)實(shí)銀行存鈔,設(shè)置睡眠時(shí)間兩秒 <br> System.out.println("正在存鈔,請稍后...");//將輸出等待 <br> Thread.sleep(4000);//將其過程等待四秒 <br> System.out.println("存款成功!");//則輸出存款成功 <br> System.out.println("您的存款金額為:"+number+"\t"+"當(dāng)前賬戶余額為:"+number); <br> //輸出存款金額 <br> System.out.println("1.是否打印憑條"+"\t"+"2.是否繼續(xù)存款"+"\t"+"3.退出"); <br> //用戶繼續(xù)選擇 <br> int sr1 = sc.nextInt();//接收用戶輸入 <br> switch(sr1){ <br> //接收用戶是否打印憑條 <br> case 1: <br> System.out.println("dce"); <br> System.out.println("打印完成,退出打印"); <br> break; <br> //接收用戶是否繼續(xù)存款 <br> case 2: <br> System.out.println("繼續(xù)存款"); <br> banking(); <br> break; <br> //接收用戶退出 <br> case 3: <br> System.out.println("您已退出存款選項(xiàng)"); <br> break; <br> //防止隨意輸入 <br> default : <br> System.out.println("您輸入有誤,請重新輸入"); <br> break; <br> } <br> }catch(Exception e){ <br> e.printStackTrace(); <br> } <br> break; <br> //輸入2則進(jìn)入取款功能 <br> case 2:System.out.println("請輸出您的取款金額:"); <br> Account account2 = new Account("小明",7000);//創(chuàng)建Account對象并傳參數(shù) <br> DrawMoney ka = new DrawMoney(account2,3000);//創(chuàng)建銀行卡取款3000元 <br> DrawMoney zhe = new DrawMoney(account2,4000);//創(chuàng)建存折取款2000元 <br> new Thread(ka).start();//開啟銀行卡線程 <br> new Thread(zhe).start();//開啟存折線程 <br> break; <br> //輸入3則退出銀行系統(tǒng) <br> case 3: <br> System.out.println("您已安全退出中國銀行系統(tǒng),感謝您的光臨!"); <br> System.exit(0);//退出指令 <br> break; <br> //防止用戶隨意輸入則進(jìn)行友情提示 <br> default : <br> System.out.println("您輸入有誤,請重新輸入"); <br> break; <br> } <br> } <br> //繼承存款金額 <br> public static void banking(){ <br> @SuppressWarnings("resource") <br> Scanner sc2 = new Scanner(System.in);//接收控制臺鍵盤輸入 <br> System.out.println("請您輸入存款金額:");//提示用戶存款金額 <br> double number = sc2.nextDouble();//接收用戶輸入金額 <br> @SuppressWarnings("unused") <br> Account account2 = new Account("asdd",number);//創(chuàng)建Accound對象 <br> System.out.println("請您將鈔票疊整齊后放入存鈔口..");//提示用戶將鈔票放入存鈔口 <br> try{ <br> Thread.sleep(2000);//模仿現(xiàn)實(shí)銀行存鈔,設(shè)置睡眠時(shí)間兩秒 <br> System.out.println("正在存鈔,請稍后...");//將輸出等待 <br> Thread.sleep(4000);//將其過程等待四秒 <br> System.out.println("存款成功!");//則輸出存款成功 <br> System.out.println("您的存款金額為:"+number+"\t"+"當(dāng)前賬戶余額為:"+number); <br> //輸出存款金額 <br> System.out.println("1.是否打印憑條"+"\t"+"\t"+"2.退出");//用戶繼續(xù)選擇 <br> int sr3 = sc2.nextInt();//接收用戶輸入 <br> switch(sr3){ <br> //接收用戶是否打印憑條 <br> case 1: <br> System.out.println("dce"); <br> System.out.println("打印完成,退出打印"); <br> break; <br> case 2: <br> System.out.println("您已退出存款選項(xiàng)"); <br> break; <br> //防止隨意輸入 <br> default : <br> System.out.println("您輸入有誤,請重新輸入"); <br> break; <br> } <br> }catch(Exception e){ <br> e.printStackTrace(); <br> } <br> } <br> } <br> ``` <br> ``` <br> package cn.chinabank;//中國銀行包 <br> //取錢類實(shí)現(xiàn)Runnable接口 <br> public class DrawMoney implements Runnable{ <br> private Account account;//私有屬性-賬戶 <br> private double money;//私有屬性-金額 <br> //構(gòu)造方法并傳值 <br> public DrawMoney(Account account,double money){ <br> this.account = account;//當(dāng)前賬戶 <br> this.money = money;//當(dāng)前金額 <br> } <br> @Override <br> public void run() { <br> while(true){ <br> //線程同步塊 <br> //相當(dāng)于將account隊(duì)形鎖住,只有執(zhí)行完代碼塊,才可以釋放,其他線程才能拿到 <br> //account必須是同一個(gè) <br> synchronized(account){ <br> //如果賬戶金額大于等于金額 <br> if(account.getNumber()&=money){ <br> account.setNumber(account.getNumber()-money);//賬戶余額減去取款金額 <br> //輸出取款成功,并顯示當(dāng)前賬戶剩余金額 <br> System.out.println("你已取款成功,您取款金額為:"+money+"元,剩余金額為:"+account.getNumber()+"元"); <br> //異常處理 <br> try{ <br> Thread.sleep(2000);//調(diào)用方法設(shè)置睡眠兩秒 <br> }catch(InterruptedException e){ <br> e.printStackTrace(); <br> } <br> //否則提示取款不成功,顯示當(dāng)前賬戶余額 <br> }else{ <br> System.out.println("對不起,您的賬戶余額不足,您當(dāng)前賬戶余額剩余"+account.getNumber()+"元");//輸出賬戶金額 <br> } <br> } <br> break; <br> } <br> } <br> ```
多線程的開發(fā)中有一個(gè)最經(jīng)典的操作案例,就是生產(chǎn)者-消費(fèi)者
生產(chǎn)者不斷生產(chǎn)產(chǎn)品,消費(fèi)者不斷取走產(chǎn)品
/**
* 生產(chǎn)者與消費(fèi)者應(yīng)用案例
* sleep與wait區(qū)別
* sleep讓當(dāng)前的線程進(jìn)入休眠狀態(tài),讓出cpu,讓其他線程執(zhí)行
* 如果用同步的話,有對象鎖的時(shí)候,是不會釋放的,只能等待此線程使用完,才可以使用
* wait會釋放對象鎖,必須等待其他線程喚醒
* @author JEEP-711
*
*/
public class ScXf {
public static void main(String[] args) {
Phones p = new Phones(null, null);//創(chuàng)建Phones對象
PhoneSc s = new PhoneSc(p);//創(chuàng)建PhoneSc對象
PhoneXf x = new PhoneXf(p);//創(chuàng)建PhoneXf對象
new Thread(s).start();//啟動生產(chǎn)者線程
new Thread(x).start();//啟動消費(fèi)者線程
}
}
/**
* 手機(jī)生產(chǎn)者,單獨(dú)的生產(chǎn)者,實(shí)現(xiàn)Runnable接口
* @author JEEP-711
*
*/
class PhoneSc implements Runnable{
private Phones phones;
public PhoneSc(Phones phones){
this.phones = phones;
}
@Override
public void run() {
//不斷地生產(chǎn)20份,生產(chǎn)的過程
for (int i = 0; i < 50; i++) {
if(i%2==0){
phones.set("金立手機(jī)", "金立手機(jī),中國造!");
}else{
phones.set("小米手機(jī)", "小米手機(jī),為發(fā)燒而生!");
}
}
}
}
/**
* 手機(jī)消費(fèi)者,顧客
* @author JEEP-711
*
*/
class PhoneXf implements Runnable{
private Phones phones;
public PhoneXf(Phones phones){
this.phones = phones;
}
@Override
public void run() {
for (int i = 0; i < 50; i++) {
phones.get();//調(diào)用消費(fèi)產(chǎn)品方法
}
}
}
/**
* 產(chǎn)品的對象,生產(chǎn)的手機(jī)
* @author JEEP-711
*
*/
class Phones{
@Override
public String toString() {
return "Phones [name=" + name + ", content=" + content + "]";
}
private String name;
private String content;
/**true表示可以生產(chǎn),false表示可以消費(fèi)
* 作為標(biāo)記,如何flag等于true表示可以生產(chǎn),如何flag等于false表示不可生產(chǎn)
* 如果flag等于false表示可以消費(fèi)狀態(tài),可以取走,flag等于true表示不能取走
* 解決重復(fù)值得問題
*/
private boolean flag = true;//表示可以生產(chǎn),false表示可以消費(fèi)
//構(gòu)造方法
public Phones(String name, String content) {
super();
this.name = name;
this.content = content;
}
//取得名稱方法
public String getName() {
return name;
}
//設(shè)置名稱方法
public void setName(String name) {
this.name = name;
}
//取得內(nèi)容方法
public String getContent() {
return content;
}
//設(shè)置內(nèi)容方法
public void setContent(String content) {
this.content = content;
}
/**
* 通過同步,解決了取值錯(cuò)誤問題
* @param name
* @param content
*/
//生產(chǎn)制造同步方法
public synchronized void set(String name, String content){
if(!flag){
try {
//調(diào)用該方法,當(dāng)前線程進(jìn)入等待池等待狀態(tài),沒有指定時(shí)間,
//需要其他線程喚醒,釋放對象鎖,讓出cpu
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.setName(name);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setContent(content);
flag = false;//表示可以消費(fèi),取走
this.notify();//喚醒在該監(jiān)視器上的一個(gè)線程
}
//消費(fèi)產(chǎn)品同步取值方法
public synchronized void get(){
if(flag){
try {
//調(diào)用該方法,當(dāng)前線程進(jìn)入等待池等待狀態(tài),沒有指定時(shí)間,
//需要其他線程喚醒,釋放對象鎖,讓出cpu
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.getName()+":"+this.getContent());
flag = true;
this.notify();
}
}
線程池是預(yù)先創(chuàng)建線程的一種技術(shù),線程池在還沒有任務(wù)到來之前,創(chuàng)建一定數(shù)量的線程,放入空閑隊(duì)列中,然后對這些資源進(jìn)行復(fù)用,減少頻繁的創(chuàng)建和銷毀對象
java里面線程池的頂級接口是Executor,是一個(gè)執(zhí)行線程的工具
線程池接口是ExecutorServise
1.java.util.concurrent包:并發(fā)編程中很常用的實(shí)用工具包
2.Executor接口:執(zhí)行已提交Runnable任務(wù)的對象
ExecutorService接口:
Executor提供了管理終止的方法,以及可能為跟蹤一個(gè)或
多個(gè)異步任務(wù)執(zhí)行狀況而發(fā)生的Future的方法
Executors類:此包中所定義的Executor、ExecutorService等的工廠和實(shí)現(xiàn)方法
在Executors類里提供了一些靜態(tài)工廠,生成一些常用的線程池
newSingleThreadExecutor:
創(chuàng)建一個(gè)單線程的線程池,這個(gè)線程池只有一個(gè)線程在工作,也就是相當(dāng)于單線程
串行執(zhí)行所有的任務(wù),如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會有一個(gè)新的線程來替代它,此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行
newFixedThreadPool:
創(chuàng)建固定大小的線程池,每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大線程池的大小一旦達(dá)到最大值就會保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會補(bǔ)充一個(gè)新線程
newCacheadThreadPool:
創(chuàng)建一個(gè)可緩存的線程池,如果線程池的大小超過了處理任務(wù)所需要的線程,那么就會回收部分空閑(60秒不執(zhí)行)的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來處理任務(wù),此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說jvm)能夠創(chuàng)建的最大線程大小
newSchediledThreadPool:
創(chuàng)建一個(gè)大小無限制的線程池,此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)需求
使用線程池的步驟:
- (1)調(diào)用Executors類的靜態(tài)工廠方法創(chuàng)建一個(gè)ExecutorService對象或ScheduledExecutorService對象,其中前者代表簡單的線程池,后者代表能以任務(wù)調(diào)度方式執(zhí)行線程的線程池
- (2)創(chuàng)建Runnable實(shí)現(xiàn)類或Callable實(shí)現(xiàn)類的實(shí)例,作為線程執(zhí)行任務(wù)
- (3)調(diào)用ExecutorService對象的submit方法來提交Runnable實(shí)例或Callable實(shí)例;或調(diào)用ScheduledExecutorService的schedule來執(zhí)行線程
- (4)當(dāng)不想提交任何任務(wù)時(shí)調(diào)用ExecutorService對象的shutdown方法來關(guān)閉線程池
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: