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

歡迎訪問 生活随笔!

生活随笔

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

java

Java-进阶:多线程2

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

目錄

一、Lock 接口

二、線程間的通信

三、線程池

四、定時(shí)器 Timer

五、多線程和異常

一、Lock 接口

1. 線程鎖

  • 是控制多個(gè)線程對共享資源進(jìn)行訪問的工具。通常,鎖提供了對共享資源的獨(dú)占訪問。一次只能有一個(gè)線程獲得鎖,對共享資源的所有訪問都需要首先獲得鎖
//鎖的使用 Lock l = new ReentrantLock(); //創(chuàng)建一個(gè)鎖對象 l.lock(); try {// access the resource protected by this lock } finally {l.unlock(); }
  • LockSynchronize更為靈活的功能:
  • boolean tryLock()僅在調(diào)用時(shí)鎖為空閑狀態(tài)才獲取該鎖。如果鎖可用,則獲取鎖,并立即返回值 true。如果鎖不可用,則此方法將立即返回值 false。

2. 同步弊端

  • 影響效率
  • 如果出現(xiàn)了嵌套鎖,容易產(chǎn)生死鎖

3. 死鎖

  • 死鎖:死鎖是指兩個(gè)以上的線程在執(zhí)行過程中,因?yàn)闋帄Z資源而產(chǎn)生的一種相互等待的現(xiàn)象

二、線程間的通信

1. wait()

  • 導(dǎo)致當(dāng)前線程處于等待狀態(tài)
  • 只有在其他線程線程中調(diào)用了notify()方法或 notifyAll()來喚醒,因?yàn)?wait()方法阻塞了線程
  • 在調(diào)用 wait方法之前,當(dāng)前線程必須擁有此對象監(jiān)視器(鎖對象),換句話說,必須在 鎖對象 上調(diào)用 wait方法(此方法只應(yīng)該由作為此對象監(jiān)視器的所有者的線程 來調(diào)用)
  • 一旦在鎖對象上調(diào)用了 wait方法,緊接著:
    • 當(dāng)前線程放棄 cpu 執(zhí)行權(quán),并等待
    • 放棄持有的 鎖對象

wait()和 sleep()比較
相同點(diǎn):使當(dāng)前線程放棄cpu執(zhí)行權(quán),處于阻塞狀態(tài)
不同點(diǎn)

  • 線程因?yàn)?sleep() 方法 處于阻塞狀態(tài)的時(shí)候,不會放棄所持有的鎖對象;線程因?yàn)?strong>wait() 處于阻塞狀態(tài)的時(shí)候,會放棄鎖對象
  • 使用條件sleep() 沒有任何特殊條件; 使用 wait() 則必須持有鎖,在鎖對象上調(diào)用**wait()**方法
  • 喚醒條件sleep() 的喚醒條件是休眠時(shí)間結(jié)束;wait() 被喚醒,只能是在其它線程中調(diào)用了同一個(gè)鎖對象的 notify() 或者 **notifyAll()**方法
  • 2. nofity()

    • 喚醒在此對象(調(diào)用wait的同一個(gè)鎖對象) 監(jiān)視器上等待的單個(gè)線程;如果所有線程都在此對象上等待,則會選擇喚醒其中一個(gè)線程
    • 直到當(dāng)前線程放棄此對象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線程
    • 被喚醒的線程將以常規(guī)方式與在該對象上主動同步的其他所有線程進(jìn)行競爭

    3. notifyAll()

    • 喚醒在此對象監(jiān)視器上等待的所有線程

    三、線程池

    1. 概述

    • 我們創(chuàng)建一個(gè)線程,只能使用一次
    • 線程池,其實(shí)就是一個(gè)容納多個(gè)線程的容器,其中的線程可以反復(fù)使用,省去了頻繁創(chuàng)建線程對象的操作,無需反復(fù)創(chuàng)建線程而消耗過多資源
    • 線程池的原理:線程池里每一個(gè)線程代碼結(jié)束后,并不會死亡,而是再次回到線程池中成為空閑狀態(tài),等待下一次被使用

    為什么要使用線程池?

  • 在 java 中,如果每個(gè)請求到達(dá)就創(chuàng)建一個(gè)新線程,開銷是相當(dāng)大的。在實(shí)際使用中,創(chuàng)建和銷毀線程花費(fèi)的時(shí)間和消耗的系統(tǒng)資源都相當(dāng)大,甚至可能要比在處理實(shí)際的用戶請求的時(shí)間和資源要多的多。
  • 除了創(chuàng)建和銷毀線程的開銷之外,活動的線程也需要消耗系統(tǒng)資源。如果在一個(gè)jvm里創(chuàng)建太多的線程,可能會使系統(tǒng)由于過度消耗內(nèi)存或“切換過度”而導(dǎo)致系統(tǒng)資源不足。
  • 為了防止資源不足,需要采取一些辦法來限制任何給定時(shí)刻處理的請求數(shù)目,盡可能減少創(chuàng)建和銷毀線程的次數(shù),特別是一些資源耗費(fèi)比較大的線程的創(chuàng)建和銷毀,盡量利用已有對象來進(jìn)行服務(wù)。
  • 線程池主要用來解決線程生命周期開銷問題和資源不足問題。通過對多個(gè)任務(wù)重復(fù)使用線程,線程創(chuàng)建的開銷就被分?jǐn)偟搅硕鄠€(gè)任務(wù)上了,而且由于在請求到達(dá)時(shí)線程已經(jīng)存在,所以消除了線程創(chuàng)建所帶來的延遲。這樣,就可以立即為請求服務(wù),使用應(yīng)用程序響應(yīng)更快。另外,通過適當(dāng)?shù)恼{(diào)整線程中的線程數(shù)目可以防止出現(xiàn)資源不足的情況。
  • 2. 創(chuàng)建線程池

    • 通常,線程池都是通過 線程池工廠 創(chuàng)建,再調(diào)用線程池中的方法獲取線程,再通過線程去執(zhí)行任務(wù)方法Executors:線程池創(chuàng)建工廠類
    • public static ExecutorService newCachedThreadPool()
      • 創(chuàng)建一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程 的線程池,但是在以前構(gòu)造的線程可用時(shí)將重用它們 (可變)
      • 對于執(zhí)行很多短期異步(短但是頻繁) 任務(wù)的程序而言,這些線程池通常可提高程序性能
      • 如果現(xiàn)有線程沒有可用的,則創(chuàng)建一個(gè)新線程并添加到池中
      • 終止并從緩存中移除那些已有 60 秒鐘未被使用的線程(折中)
    • public static ExecutorService newFixedThreadPool(int nThreads)
      • 創(chuàng)建一個(gè)可重用固定線程數(shù)的線程池,以共享的無界隊(duì)列方式來運(yùn)行這些線程
      • 如果在所有線程處于活動狀態(tài)時(shí)提交附加任務(wù),則在有可用線程之前,附加任務(wù)將在隊(duì)列中等待
    • public static ExecutorService newSingleThreadExecutor()
      • 創(chuàng)建一個(gè)使用單個(gè) worker 線程的 Executor,以無界隊(duì)列方式來運(yùn)行該線程
      • 可保證順序地執(zhí)行各個(gè)任務(wù)
    • 以上方法返回了一個(gè)ExecutorService,該對象表示一個(gè)線程池,它可以執(zhí)行 Runable對象代表的線程。

    3. 提交任務(wù)

    • Runnable 接口
    • Callable 接口類似于 Runnable,用來指定線程的任務(wù)。其中的 call() 方法,用來返回線程任務(wù)執(zhí)行完畢后的結(jié)果,call方法可拋出異常
    • ExecutorService:線程池類
    • <T> Future<T> **submit**(Callable<T> task):獲取線程池中的某一個(gè)線程對象,并執(zhí)行線程中的call()方法
    • Future接口:用來記錄線程任務(wù)執(zhí)行完畢后產(chǎn)生的結(jié)果
      • get()獲取 Future對象中封裝的數(shù)據(jù)結(jié)果
    • void shutdown():啟動一次順序關(guān)閉,執(zhí)行以前提交的任務(wù),但 不接受新任務(wù)
    • shutdownNow()方法: 試圖停止所有正在執(zhí)行的活動任務(wù),暫停處理正在等待的任務(wù),并返回等待執(zhí)行的任務(wù)列表。

    4. 使用線程池中線程對象的步驟:

    • 創(chuàng)建線程池對象
    • 創(chuàng)建 Runnable 接口/Callable接口 子類對象
    • 提交 Runnable 接口/Callable接口 子類對象
    • 關(guān)閉線程池
    public class ThreadPool {public static void main(String[] args) throws ExecutionException, InterruptedException {//創(chuàng)建一個(gè)newCachedThreadPoolExecutorService executorService = Executors.newFixedThreadPool(5);//操作線程池//向線程池提交任務(wù)executorService.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello, thread pool");}});//Callable接口的使用Future<Integer> future = executorService.submit(new Callable<Integer>() {@Overridepublic Integer call() throws Exception {TimeUnit.SECONDS.sleep(3);int sum = 0;for (int i = 0; i < 10; i++) {sum += i;}return sum;}});System.out.println(future);System.out.println(future.get());} }

    四、定時(shí)器 Timer

    1. 概述

    • 調(diào)度定時(shí)任務(wù),幫助我們在稍后的時(shí)刻執(zhí)行定時(shí)任務(wù)。一種工具,線程用其安排以后在后臺線程中執(zhí)行的任務(wù)。可安排任務(wù) 執(zhí)行一次,或者 定期重復(fù)執(zhí)行

    2. TimerTask 定時(shí)任務(wù)

    • 定時(shí)任務(wù):TimerTask對象表示定時(shí)任務(wù)
    • Timer調(diào)度定時(shí)任務(wù),定時(shí)任務(wù)的內(nèi)容由TimerTask的run方法 運(yùn)行決定
    • 在 timer 中所有的定時(shí)任務(wù)都是運(yùn)行在同一個(gè)線程中
  • cancel 取消定時(shí)任務(wù)
    • 如果利用TimerTask的cancel要取消定時(shí)任務(wù),在定時(shí)任務(wù)已經(jīng)開始運(yùn)行時(shí), 調(diào)用cancel方法,是沒有效果
      利用Timer的cancel方法取消定時(shí)任務(wù),其實(shí)是終止Timer本身
    public class TimerDemo {public static void main(String[] args) {//定義一個(gè)定時(shí)器// 在timer中所有的定時(shí)任務(wù)都是運(yùn)行在同一個(gè)線程中Timer timer = new Timer(); //默認(rèn)不是守護(hù)線程//在定時(shí)器上調(diào)度,定時(shí)任務(wù)timer.schedule(new MyTimerTask(), 3000);timer.schedule(new MyTimerTask(), 1000);//調(diào)度器重復(fù)執(zhí)行定時(shí)任務(wù)timer.schedule(new MyTimerTask(timer), 0, 2000);} }class MyTimerTask extends TimerTask {Timer timer;public MyTimerTask(Timer timer) {this.timer = timer;}@Overridepublic void run() {//在輸出之前,取消定時(shí)任務(wù)//cancel();//利用Timer的cancel方法取消定時(shí)任務(wù),其實(shí)timer的cance方法,是終止Timer本身timer.cancel();System.out.println("hello timer");} }

    五、多線程和異常

    • 在 Thread 類中,不可以拋出編譯型異常,但是可以拋出運(yùn)行時(shí)異常
    • 當(dāng) 運(yùn)行時(shí)異常拋出線程(溢出線程),能不能捕獲?

    java語言,并不能直接用try-catch代碼塊捕獲,溢出線程的異常,這是java語言實(shí)現(xiàn)上的一個(gè)遺憾,但是,并不是說,溢出線程的異常開發(fā)者就沒辦法捕獲了。—> Thread.UncaughtExceptionHandler

    • static setDefaultUncaughtExceptionHandler,處理所有線程中未捕獲的異常(溢出線程的異常)
    • setUncaughtExceptionHandler,處理某一個(gè)線程中的未捕獲的異常(溢出線程的異常)
    public class supplement01 {public static void main(String[] args) {//我們可以通過設(shè)置UncaughtExceptionHandler對象,讓該對象捕獲溢出線程的異常// callback 回調(diào)Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {// 這個(gè)方法,會在日志模塊 -》 將這些異常信息,通過流保存到文件中//處理溢出線程的異常System.out.println("DefaultUncaughtExceptionHandler");}});//在主線程中捕獲異常CatchThreadException1 catchThreadException = new CatchThreadException1();catchThreadException.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {System.out.println("Thread t" + e.getMessage());}});try{//試圖在主線程捕獲子線程拋出的異常catchThreadException.start();}catch (Exception e) {System.out.println("我捕獲到了異常");}} }class CatchThreadException extends Thread {@Overridepublic void run() {//將異常拋出run方法之外,就等價(jià)于將該拋出了線程throw new RuntimeException("測試拋出線程的異常");} }class CatchThreadException1 extends Thread {@Overridepublic void run() {//將異常拋出run方法之外,就等價(jià)于將該拋出了線程throw new RuntimeException("測試拋出線程的異常");} } ew RuntimeException("測試拋出線程的異常");} }class CatchThreadException1 extends Thread {@Overridepublic void run() {//將異常拋出run方法之外,就等價(jià)于將該拋出了線程throw new RuntimeException("測試拋出線程的異常");} }

    總結(jié)

    以上是生活随笔為你收集整理的Java-进阶:多线程2的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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