日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

JavaSE | 多线程

發(fā)布時(shí)間:2023/12/18 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaSE | 多线程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

一、實(shí)現(xiàn)線(xiàn)程的方式一:繼承java.lang.Thread類(lèi)   1、步驟   (1)編寫(xiě)線(xiàn)程類(lèi),繼承java.lang.Thread類(lèi)   (2)重寫(xiě)public void run(){} 在run()的方法體中,編寫(xiě)的代碼就是該線(xiàn)程的線(xiàn)程體   (3)創(chuàng)建線(xiàn)程對(duì)象:new(4)啟動(dòng)線(xiàn)程:調(diào)用start()二、實(shí)現(xiàn)多線(xiàn)程:實(shí)現(xiàn)java.lang.Runnable接口   1、步驟   (1)編寫(xiě)線(xiàn)程類(lèi),實(shí)現(xiàn)java.lang.Runnable接口   (2)實(shí)現(xiàn)public void run(){} 把該線(xiàn)程需要完成的任務(wù),寫(xiě)在run()中   (3)創(chuàng)建線(xiàn)程對(duì)象   (4)啟動(dòng)線(xiàn)程:start()       因?yàn)镽unnable接口和Object中都沒(méi)有start方法,只有Thread類(lèi)中有start   所以啟動(dòng)線(xiàn)程必須有Thread的對(duì)象。      相當(dāng)于用Thread對(duì)象做為當(dāng)前線(xiàn)程對(duì)象的代理對(duì)象,幫我們啟動(dòng)線(xiàn)程。

共享變量--線(xiàn)程的交互
而進(jìn)程之間的交互特別慢??1套系統(tǒng)即1個(gè)進(jìn)程??rmi --->EJB --> spring

Thread常用方法:   (1)靜態(tài)方法:currentThread()獲取當(dāng)前線(xiàn)程對(duì)象   (2)獲取線(xiàn)程名稱(chēng):getName()   (3)獲取線(xiàn)程的優(yōu)先級(jí):getPriority()    MIN_PRIORITY:最小優(yōu)先級(jí):1MAX_PRIORITY:最大優(yōu)先級(jí):10NORM_PRIORITY:默認(rèn)優(yōu)先級(jí),普通優(yōu)先級(jí):5  main線(xiàn)程的默認(rèn)優(yōu)先級(jí)是5,通過(guò)主線(xiàn)程創(chuàng)建和啟動(dòng)的線(xiàn)程,默認(rèn)優(yōu)先級(jí)和它一樣    換句話(huà)說(shuō),誰(shuí)把你創(chuàng)建和啟動(dòng)的,你的默認(rèn)優(yōu)先級(jí)就和它一樣。當(dāng)然可以自己修改。       優(yōu)先級(jí)高的,獲取CPU調(diào)用的概率相對(duì)高,但是不是說(shuō)低沒(méi)有機(jī)會(huì)。    優(yōu)先級(jí)必須設(shè)置為[1,10]之間,而且必須在啟動(dòng)之前設(shè)置。 控制線(xiàn)程的一些方法:   (1)靜態(tài)方法:sleep(毫秒) 1秒 = 1000毫秒   (2)非靜態(tài)的方法:     join() 加塞 無(wú)限制阻塞下去     join(時(shí)間) 只阻塞指定時(shí)間   (3)靜態(tài)方法:yield()      暫停當(dāng)前線(xiàn)程,讓出本次的CPU資源   (4)setDaemon(boolean on):守護(hù)線(xiàn)程      守護(hù)線(xiàn)程,只為其他線(xiàn)程服務(wù)的,如果被守護(hù)線(xiàn)程都死亡了,守護(hù)線(xiàn)程自動(dòng)結(jié)束了。例如垃圾回收線(xiàn)程     isDaemon():判斷某個(gè)線(xiàn)程是否是守護(hù)線(xiàn)程    (5)停止線(xiàn)程      stop()已過(guò)時(shí),現(xiàn)在停止線(xiàn)程,使用一些條件變量來(lái)控制線(xiàn)程。
    跳出run方法:return、throw

線(xiàn)程安全問(wèn)題

并發(fā)和并行的概念

?

多線(xiàn)程并發(fā),多個(gè)去搶,只有一個(gè)執(zhí)行,單核只有并發(fā)
多個(gè)軟件進(jìn)程并行,多核

?

public class TestThreadSafe {public static void main(String[] args) {final ShareData sd = new ShareData();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {sd.username = "alex";try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1 = " + sd.username);}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {sd.username = "kris";try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t2 = " + sd.username);}});t1.start();t2.start();System.out.println("main方法執(zhí)行完畢。。。");} }class ShareData{public String username; } View Code

t1、t2都要sleep 1s,則main線(xiàn)程最先執(zhí)行; 共享內(nèi)存(堆、方法區(qū))

一個(gè)線(xiàn)程即一個(gè)??臻g,堆內(nèi)存是共享的;?執(zhí)行方法即壓棧--棧幀(方法的所有內(nèi)容) ;方法執(zhí)行完就會(huì)彈棧

?

線(xiàn)程安全問(wèn)題:當(dāng)多個(gè)線(xiàn)程使用同一份“資源”時(shí),其中一個(gè)線(xiàn)程對(duì)“資源”的修改,影響了其他線(xiàn)程。多線(xiàn)程并發(fā)執(zhí)行時(shí),對(duì)共享內(nèi)存中的共享對(duì)象中的共享屬性進(jìn)行修改所導(dǎo)致的數(shù)據(jù)沖突問(wèn)題; 下次我們?nèi)绾闻袛辔覀兊某绦蚴欠裼芯€(xiàn)程安全問(wèn)題?(1)多個(gè)線(xiàn)程; (2)有共享數(shù)據(jù); (3)多條語(yǔ)句操作共享數(shù)據(jù)    多條語(yǔ)句的中間隨時(shí)可能失去CPU資源,被其他線(xiàn)程操作    如何避免? 加鎖; 用同步:   1、同步代碼塊    synchronized(鎖對(duì)象){       需要加鎖的代碼     };鎖對(duì)象的選擇:   (1)鎖對(duì)象可以是任意類(lèi)型的對(duì)象; (2)保證多個(gè)線(xiàn)程要共用同一個(gè)鎖對(duì)象 ,這個(gè)鎖對(duì)象也稱(chēng)為監(jiān)視器對(duì)象 2、同步方法【修飾符】synchronized 返回值類(lèi)型 方法名(【形參列表】)【拋出的異常列表】{     } 鎖對(duì)象沒(méi)的選:   (1)靜態(tài)方法:當(dāng)前類(lèi)的Class對(duì)象; (2)非靜態(tài)方法:this(要謹(jǐn)慎)    * 提醒:   (1)鎖的代碼的范圍,太大或太小都不行; 一般考慮一次任務(wù),并且保證所有操作共享數(shù)據(jù)的代碼都鎖進(jìn)去了。    例如,這里的條件判斷hasTicket()和買(mǎi)票的buy()代碼    (2)一定要確保鎖對(duì)象是同一個(gè)   什么時(shí)候釋放鎖?   (1)把同步代碼塊或同步方法的代碼執(zhí)行完,自動(dòng)釋放

?

?繼承Thread父類(lèi)

同步代碼塊

線(xiàn)程開(kāi)始執(zhí)行同步代碼塊之前,必須先獲得對(duì)同步監(jiān)視器的鎖定,換句話(huà)說(shuō)沒(méi)有獲得對(duì)同步監(jiān)視器的鎖定,就不能進(jìn)入同步代碼塊的執(zhí)行,線(xiàn)程就會(huì)進(jìn)入阻塞狀態(tài),直到對(duì)方釋放了對(duì)同步監(jiān)視器對(duì)象的鎖定。

任何時(shí)刻只能有一個(gè)線(xiàn)程可以獲得對(duì)同步監(jiān)視器的鎖定,當(dāng)同步代碼塊執(zhí)行結(jié)束后,該線(xiàn)程自然會(huì)釋放對(duì)同步監(jiān)視器對(duì)象的鎖定。

Java程序運(yùn)行使用任何對(duì)象來(lái)作為同步監(jiān)視器對(duì)象,只要保證共享資源的這幾個(gè)線(xiàn)程,鎖的是同一個(gè)同步監(jiān)視器對(duì)象即可

選擇同步共享資源對(duì)象作為同步監(jiān)視器對(duì)象

//方法一:同步代碼塊public void safe(){while(ts.hasTicket()){synchronized (ts) { //synchronized(同步監(jiān)視器對(duì)象){ 需要加鎖的代碼 };if(ts.hasTicket()){String buy = ts.buy();System.out.println(Thread.currentThread().getName() +"賣(mài)了張票" + buy);}}}}

同步方法

與同步代碼塊對(duì)應(yīng)的,Java的多線(xiàn)程安全支持還提供了同步方法,同步方法就是使用synchronized關(guān)鍵字來(lái)修飾某個(gè)方法,則該方法稱(chēng)為同步方法。對(duì)于同步方法而言,無(wú)須顯式指定同步監(jiān)視器,靜態(tài)方法的同步監(jiān)視器對(duì)象是當(dāng)前類(lèi)的Class對(duì)象,非靜態(tài)方法的同步監(jiān)視器對(duì)象是調(diào)用當(dāng)前方法的this對(duì)象。

//方法二:同步方法;鎖對(duì)象是當(dāng)前類(lèi)的Class對(duì)象Window.classpublic static synchronized void safe(){ if(ts.hasTicket()){String buy = ts.buy();System.out.println(Thread.currentThread().getName() + "賣(mài)了張票" + buy);}}

?

?

?實(shí)現(xiàn)Runnable接口的方式

選擇this對(duì)象作為同步監(jiān)視器對(duì)象

如果線(xiàn)程是繼承Thread類(lèi)實(shí)現(xiàn)的,那么把同步監(jiān)視器對(duì)象換成this,那么就沒(méi)有起到作用,仍然會(huì)發(fā)生線(xiàn)程安全問(wèn)題。因?yàn)閮蓚€(gè)線(xiàn)程的this對(duì)象是不同的。

但是如果線(xiàn)程是實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)的,那么如果兩個(gè)線(xiàn)程共用同一個(gè)Runnable接口實(shí)現(xiàn)類(lèi)對(duì)象作為target的話(huà),就可以把同步監(jiān)視器對(duì)象換成this。

//選擇this對(duì)象作為同步監(jiān)視器對(duì)象public void safe(){while(true){synchronized (this) {if(ts.hasTicket()){String buy = ts.buy();System.out.println(Thread.currentThread().getName() + "賣(mài)了張票" + buy);}}}}

同步方法

//方法二:同步方法;非靜態(tài)方法的同步監(jiān)視器對(duì)象是調(diào)用當(dāng)前方法的this對(duì)象。public synchronized void safe(){if(ts.hasTicket()){String buy = ts.buy();System.out.println(Thread.currentThread().getName() + "賣(mài)了張票" + buy);}}

?兩種實(shí)現(xiàn)線(xiàn)程方式的區(qū)別:

  ?1、繼承Thread類(lèi)
  (1)啟動(dòng)線(xiàn)程比較簡(jiǎn)單
  ?(2)可能會(huì)遇到單繼承的限制
  (3)選擇鎖對(duì)象,必須是靜態(tài)的,或當(dāng)前類(lèi).class
  
  ?2、實(shí)現(xiàn)Runnable接口
  (1)啟動(dòng)線(xiàn)程需要借助一個(gè)Thread類(lèi)的對(duì)象
  (2)沒(méi)有單繼承的限制
  ?(3)選擇鎖對(duì)象,可以使用this,或者別的

?

?生產(chǎn)者與消費(fèi)者問(wèn)題

該問(wèn)題描述了兩個(gè)(多個(gè))共享固定大小緩沖區(qū)的線(xiàn)程——即所謂的“生產(chǎn)者”和“消費(fèi)者”    ——在實(shí)際運(yùn)行時(shí)會(huì)發(fā)生的問(wèn)題。生產(chǎn)者的主要作用是生成一定量的數(shù)據(jù)放到緩沖區(qū)中,然后重復(fù)此過(guò)程。 與此同時(shí),消費(fèi)者也在緩沖區(qū)消耗這些數(shù)據(jù)。 該問(wèn)題的關(guān)鍵就是要保證生產(chǎn)者不會(huì)在緩沖區(qū)滿(mǎn)時(shí)加入數(shù)據(jù),消費(fèi)者也不會(huì)在緩沖區(qū)中空時(shí)消耗數(shù)據(jù)。
問(wèn)題:   (1)數(shù)據(jù)的緩沖區(qū)是有限的-->需要協(xié)作   (2)數(shù)據(jù)是共享的-->線(xiàn)程安全問(wèn)題   
如何解決?   (1)協(xié)作的問(wèn)題:線(xiàn)程通信 wait()和notify()/notifyAll()   wait()和notify()方法必須由“鎖”對(duì)象,或監(jiān)視器對(duì)象來(lái)調(diào)用。    因?yàn)槎鄠€(gè)線(xiàn)程之間通信就可以依據(jù)這個(gè)“鎖”對(duì)象,他們直接溝通的橋梁。    IllegalMonitorStateException:非法的監(jiān)視器對(duì)象 什么時(shí)候才有監(jiān)視器對(duì)象?在同步代碼塊或同步方法中,選擇的鎖對(duì)象才是監(jiān)視器對(duì)象 (2)線(xiàn)程安全問(wèn)題:同步、加鎖 當(dāng)有多個(gè)生產(chǎn)者與多個(gè)消費(fèi)者時(shí)?   (1)當(dāng)wait()被喚醒后,要記得重新判斷條件,所以這里可以用while,或if..else(2)notify必須換成notifyAll()    wait()和notify()/notifyAll()在哪里?   在java.lang.Object類(lèi)中聲明的,因?yàn)檎{(diào)用它的對(duì)象不是線(xiàn)程對(duì)象,而是“鎖”對(duì)象,   因?yàn)椤版i”對(duì)象不知道是什么類(lèi)型,是任意類(lèi)型,所以只能聲明在Object類(lèi)中。因?yàn)镺bject中的方法,才能保證所有對(duì)象都有。       例如:    快餐店,廚房的廚師與服務(wù)員就屬于生產(chǎn)者與消費(fèi)者,他倆之間共同操作工作臺(tái)上的“菜”,    廚師屬于生產(chǎn)者(負(fù)責(zé)往工作臺(tái)上放“菜”),服務(wù)員屬于消費(fèi)者(從工作臺(tái)上取走“菜”),多個(gè)生產(chǎn)者消費(fèi)者,notify( )的是所有同一個(gè)鎖對(duì)象的,等待的線(xiàn)程都有可能被喚醒,因此喚醒的可能是另一個(gè)生產(chǎn)者;兩個(gè)生產(chǎn)者互相喚醒,就會(huì)一直生產(chǎn)了;解決方案是:1)生產(chǎn)者喚醒消費(fèi)者,消費(fèi)者喚醒生產(chǎn)者,但notify沒(méi)有這個(gè)功能;
      2)每次被喚醒的線(xiàn)程,重新判斷條件,不要走下面的,再回去,用while循環(huán);

?

?

?單例設(shè)計(jì)模式:(高頻面試題)

單例:唯一的對(duì)象 * 某個(gè)類(lèi)在整個(gè)系統(tǒng)中只有唯一的對(duì)象,不會(huì)出現(xiàn)第二個(gè)對(duì)象。 如何實(shí)現(xiàn)單例?   (1)構(gòu)造器私有化:避免隨意new對(duì)象   (2)在類(lèi)中創(chuàng)建這個(gè)唯一的對(duì)象,并且保存:供外界使用    兩種形式: 1、餓漢式   無(wú)論別人現(xiàn)在是否需要這個(gè)對(duì)象,我都創(chuàng)建,在初始化這個(gè)類(lèi)時(shí),就創(chuàng)建 2、懶漢式   只有在別人來(lái)拿這個(gè)對(duì)象時(shí)(不得不創(chuàng)建時(shí)),才會(huì)創(chuàng)建 * 單例唯一改變的就是創(chuàng)建對(duì)象的位置和獲取對(duì)象的方式而已,其他的沒(méi)有變。* 回憶:枚舉,當(dāng)某個(gè)類(lèi)型的對(duì)象是有限個(gè)

?

?

餓漢式單例模式

class Hungry{ //餓漢模式// 在類(lèi)中創(chuàng)建這個(gè)唯一的對(duì)象,并且保存:供外界使用public static final Hungry INSTANCE = new Hungry(); //靜態(tài)的在類(lèi)初始化時(shí)初始化;//在初始化這個(gè)這個(gè)類(lèi)時(shí)就創(chuàng)建這個(gè)對(duì)象,不管別人是否使用;private Hungry() { //構(gòu)造器私有化,避免隨意私有化對(duì)象 }public void test(){System.out.println("餓漢式");}} class Hungry2{ //餓漢模式// 在類(lèi)中創(chuàng)建這個(gè)唯一的對(duì)象,并且保存:供外界使用public static final Hungry2 INSTANCE = new Hungry2(); //在初始化這個(gè)這個(gè)類(lèi)時(shí)就創(chuàng)建這個(gè)對(duì)象,不管別人是否使用;private Hungry2() { //構(gòu)造器私有化,避免隨意私有化對(duì)象 }public void test(){System.out.println("餓漢式");}public static Hungry2 getInstance() {return INSTANCE;}}enum Hungry3{INSTANSE;public void test(){System.out.println("餓漢式模式");}}

?

懶漢模式

public class TestSingle {static Lazy l1;static Lazy l2;public static void main(String[] args) { Thread t1 = new Thread(){public void run(){ //匿名內(nèi)部類(lèi)創(chuàng)建的線(xiàn)程對(duì)象;l1 = Lazy.getInstance();}};t1.start();//等它們執(zhí)行完,再打印它 Thread t2 = new Thread(){public void run(){l2 = Lazy.getInstance();}};t2.start();//等它們執(zhí)行完,再打印它try {t1.join();t2.join();} catch (InterruptedException e) {// TODO Auto-generated catch block e.printStackTrace();}System.out.println(l1); //打印hash碼看是否一樣; System.out.println(l2); //它們兩個(gè)結(jié)果不一樣,判斷出new了兩個(gè)對(duì)象 } }class Lazy{private static Lazy instance;public Lazy() {super();}public static Lazy getInstance(){ //不能寫(xiě)成 return new Lazy();這樣子是調(diào)一次new一次;if(instance == null){ //有可能一個(gè)線(xiàn)程剛剛判斷為null,CPU被搶走了,另外一個(gè)線(xiàn)程也被判為null//synchronized (Lazy.class) {// if(Lazy.class == null){ //存在線(xiàn)程安全問(wèn)題instance = new Lazy(); //保存到一個(gè)變量里邊; }//}//}return instance;}}

加鎖--->>>

?

    InnerLazy.method(); // 調(diào)用外部類(lèi)的時(shí)候就沒(méi)有創(chuàng)建內(nèi)部類(lèi)對(duì)象
    InnerLazy instance = InnerLazy.Inner.instance;
    //只有在別人來(lái)拿這個(gè)對(duì)象時(shí)(不得不創(chuàng)建時(shí)),才會(huì)創(chuàng)建內(nèi)部類(lèi)對(duì)象

class Lazy{private static Lazy instance;public Lazy() {super();}public static Lazy getInstance(){ //不能寫(xiě)成 return new Lazy();這樣子是調(diào)一次new一次;if(instance == null){synchronized (Lazy.class) {if(Lazy.class == null){ //存在線(xiàn)程安全問(wèn)題Lazy instance = new Lazy(); //保存到一個(gè)變量里邊; }}}return instance;}}//內(nèi)部類(lèi)的方式 class InnerLazy{private InnerLazy() {}public static void method() {System.out.println("外部類(lèi)的靜態(tài)方法"); }static class Inner{public static InnerLazy instance = new InnerLazy();static{System.out.println("內(nèi)部類(lèi)的靜態(tài)變量");}}}

?

?

wait方法和sleep方法的區(qū)別?

* (1)wait在Object類(lèi)中,sleep在Thread類(lèi)中聲明
* (2)wait通過(guò)“鎖,監(jiān)視器”對(duì)象,sleep通過(guò)Thread類(lèi)名調(diào)用
* (3)wait方法使得當(dāng)前線(xiàn)程進(jìn)入阻塞狀態(tài)后,會(huì)釋放鎖;
* sleep方法使得當(dāng)前線(xiàn)程進(jìn)入阻塞狀態(tài)后,仍然持有鎖;

yield()、sleep和wait的區(qū)別?

* (1)yield()不會(huì)阻塞線(xiàn)程,只是暫停線(xiàn)程一次,回到就緒狀態(tài)
* (2)sleep和wait會(huì)阻塞線(xiàn)程

?線(xiàn)程池

不要頻繁的去創(chuàng)建線(xiàn)程,而是給個(gè)固定的,用時(shí)拿去用,用完還回來(lái),可以重復(fù)利用的效果;? 數(shù)據(jù)庫(kù)的連接池也是這樣;

public class TestThreadPool {public static void main(String[] args) {// 構(gòu)建線(xiàn)程池ExecutorService executorService = Executors.newSingleThreadExecutor(); //創(chuàng)建單一線(xiàn)程,只有一個(gè)線(xiàn)程去執(zhí)行ExecutorService executorService1 = Executors.newFixedThreadPool(5);//可以指定線(xiàn)程的個(gè)數(shù)ExecutorService executorService2 = Executors.newCachedThreadPool(); //循環(huán)10次,它有可能創(chuàng)建5/6/7/8/9/10個(gè)線(xiàn)程都有可能for (int i = 0; i <= 10; i++){executorService2.submit(new Runnable() {public void run() {System.out.println(Thread.currentThread().getName());}});}} }

?

Executors.java return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); ThreadPoolExecutor等同于構(gòu)建了線(xiàn)程池的構(gòu)建對(duì)象;LinkedBlockingQueue阻塞式隊(duì)列; JDK1.6之后增加兩個(gè)新隊(duì)列BlockingQueue阻塞式隊(duì)列(從隊(duì)列中去取數(shù)據(jù),取不到就一直阻塞直到取到為止;往里邊放如果放不進(jìn)去就一直等待直到放進(jìn)去)和Deque雙端隊(duì)列(兩頭都可以去取)---Kafka底層中用到這個(gè)

?

轉(zhuǎn)載于:https://www.cnblogs.com/shengyang17/p/10101598.html

總結(jié)

以上是生活随笔為你收集整理的JavaSE | 多线程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。