Java-進階:多線程2

目錄

一、Lock 接口

二、線程間的通信

三、線程池

四、定時器 Timer

五、多線程和異常

一、Lock 接口

1. 線程鎖

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

2. 同步弊端

  • 影響效率
  • 如果出現了嵌套鎖,容易產生死鎖

3. 死鎖

  • 死鎖:死鎖是指兩個以上的線程在執行過程中,因為爭奪資源而產生的一種相互等待的現象

二、線程間的通信

1. wait()

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

wait()sleep()比較
相同點:使當前線程放棄cpu執行權,處于阻塞狀態
不同點

  1. 線程因為 sleep() 方法 處于阻塞狀態的時候,不會放棄所持有的鎖對象;線程因為wait() 處于阻塞狀態的時候,會放棄鎖對象
  2. 使用條件sleep() 沒有任何特殊條件; 使用 wait() 則必須持有鎖,在鎖對象上調用**wait()**方法
  3. 喚醒條件sleep() 的喚醒條件是休眠時間結束;wait() 被喚醒,只能是在其它線程中調用了同一個鎖對象的 notify() 或者 **notifyAll()**方法

2. nofity()

  • 喚醒在此對象(調用wait的同一個鎖對象) 監視器上等待的單個線程;如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程
  • 直到當前線程放棄此對象上的鎖定,才能繼續執行被喚醒的線程
  • 被喚醒的線程將以常規方式與在該對象上主動同步的其他所有線程進行競爭

3. notifyAll()

  • 喚醒在此對象監視器上等待的所有線程

三、線程池

1. 概述

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

為什么要使用線程池?

  1. 在 java 中,如果每個請求到達就創建一個新線程,開銷是相當大的。在實際使用中,創建和銷毀線程花費的時間和消耗的系統資源都相當大,甚至可能要比在處理實際的用戶請求的時間和資源要多的多。
  2. 除了創建和銷毀線程的開銷之外,活動的線程也需要消耗系統資源。如果在一個jvm里創建太多的線程,可能會使系統由于過度消耗內存或“切換過度”而導致系統資源不足。
  3. 為了防止資源不足,需要采取一些辦法來限制任何給定時刻處理的請求數目,盡可能減少創建和銷毀線程的次數,特別是一些資源耗費比較大的線程的創建和銷毀,盡量利用已有對象來進行服務。
  4. 線程池主要用來解決線程生命周期開銷問題和資源不足問題。通過對多個任務重復使用線程,線程創建的開銷就被分攤到了多個任務上了,而且由于在請求到達時線程已經存在,所以消除了線程創建所帶來的延遲。這樣,就可以立即為請求服務,使用應用程序響應更快。另外,通過適當的調整線程中的線程數目可以防止出現資源不足的情況。

2. 創建線程池

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

3. 提交任務

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

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

  • 創建線程池對象
  • 創建 Runnable 接口/Callable接口 子類對象
  • 提交 Runnable 接口/Callable接口 子類對象
  • 關閉線程池
public class ThreadPool {public static void main(String[] args) throws ExecutionException, InterruptedException {//創建一個newCachedThreadPoolExecutorService executorService = Executors.newFixedThreadPool(5);//操作線程池//向線程池提交任務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());}
}

四、定時器 Timer

1. 概述

  • 調度定時任務,幫助我們在稍后的時刻執行定時任務。一種工具,線程用其安排以后在后臺線程中執行的任務。可安排任務 執行一次,或者 定期重復執行

2. TimerTask 定時任務

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

五、多線程和異常

  • 在 Thread 類中,不可以拋出編譯型異常,但是可以拋出運行時異常
  • 當 運行時異常拋出線程(溢出線程),能不能捕獲?

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

  • static setDefaultUncaughtExceptionHandler,處理所有線程中未捕獲的異常(溢出線程的異常)
  • setUncaughtExceptionHandler,處理某一個線程中的未捕獲的異常(溢出線程的異常)
public class supplement01 {public static void main(String[] args) {//我們可以通過設置UncaughtExceptionHandler對象,讓該對象捕獲溢出線程的異常// callback 回調Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread t, Throwable e) {// 這個方法,會在日志模塊 -》 將這些異常信息,通過流保存到文件中//處理溢出線程的異常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方法之外,就等價于將該拋出了線程throw new RuntimeException("測試拋出線程的異常");}
}class CatchThreadException1 extends Thread {@Overridepublic void run() {//將異常拋出run方法之外,就等價于將該拋出了線程throw new RuntimeException("測試拋出線程的異常");}
}
ew RuntimeException("測試拋出線程的異常");}
}class CatchThreadException1 extends Thread {@Overridepublic void run() {//將異常拋出run方法之外,就等價于將該拋出了線程throw new RuntimeException("測試拋出線程的異常");}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386172.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386172.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386172.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java周總結1

一、計算機高級編程語言類型&#xff1a; a.編譯型 b.解釋型 Hello.java Java源文件 編譯 Hello.class 字節碼文件 解釋 01101100.... &#xff08;二進制&#xff09;機器碼指令 computer…

MMKV集成與原理,先收藏了

標準文檔流 標準文檔流&#xff0c;指的是元素排版布局過程中&#xff0c;元素會默認自動從左往右&#xff0c;從上往下的流式排列方式。前面內容發生了變化&#xff0c;后面的內容位置也會隨著發生變化。 HTML就是一種標準文檔流文件 HTML中的標準文檔流特點通過兩種方式體現…

Java周總結3

撰寫第三周課程總結及實驗報告&#xff08;一&#xff09; Java實驗報告 班級 計科一班 學號 20188375 姓名 湯云云 完成時間 評分等級 實驗一 Java開發環境與簡單Java程序 一、 實驗目的 &#xff08;1&#xff09; 熟悉JDK開…

MMKV集成與原理,吊打面試官系列!

前言 校招 -1 年 這個階段還屬于成長期&#xff0c;更需要看重的是你的基礎和熱情。對于 JS 基礎&#xff0c;計算機基礎&#xff0c;網絡通信&#xff0c;算法等部分的要求會相對高一些。畢竟這個階段比較難考察你的業務項目中的沉淀&#xff0c;所以只能從基礎部分入手考察。…

CV2攝像頭人臉、人眼、微笑等檢測

import cv2face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml)#人臉 eye_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_eye.xml)#人眼 smile_cascadecv2.CascadeClassifier(cv2.data.haarcascades haa…

MMKV集成與原理,成功跳槽阿里!

前言 在初學前端的時候&#xff0c;我們總會遇到一些問題&#xff0c;我們可以在網上看到很多關于前端的這些問題&#xff1a; 你們都是怎么學web前端的&#xff1f; 零基礎&#xff0c;怎么自學好前端&#xff1f; 前端需要學多久&#xff0c;都學哪些知識&#xff1f; 想成為…

第四周課程總結試驗報告(二)

Java實驗報告 實驗二 Java簡單類與對象 一、 實驗目的 &#xff08;1&#xff09; 掌握類的定義&#xff0c;熟悉屬性、構造函數、方法的作用&#xff0c;掌握用類作為類型聲明變量和方法返回值&#xff1b; &#xff08;2&#xff09; 理解類和對象的區別&#xff0c;掌握構造…

MMKV集成與原理,薪資翻倍

畢業工作一年之后&#xff0c;有了轉行的想法&#xff0c;偶然接觸到程序員這方面&#xff0c;產生了濃厚且強烈的興趣&#xff0c;開始學習前端&#xff0c;成功收割了大廠offer&#xff0c;開始了我的程序員生涯。 在自學過程中有過一些小廠的面試經歷&#xff0c;也在一些小…

Spring入門與常用配置

什么是Spring Spring&#xff1a;SE/EE開發的一站式框架。 一站式框架&#xff1a;有EE開發的每一層解決方案。 WEB層 &#xff1a;SpringMVC Service層 &#xff1a;Spring的Bean管理&#xff0c;Spring聲明式事務 DAO層 &#xff1a;Spring的Jdbc模板&#xff0c;Spring的ORM…

MMKV集成與原理,詳細學習指南

前言 本文主要是javascript和css方面的基礎面試題&#xff0c;適合面試前以及平時復習食用。 基礎知識是前端一面必問的&#xff0c;如果你在基礎知識這一塊翻車了&#xff0c;就算你框架玩的再6&#xff0c;webpack、git、node學習的再好也無濟于事&#xff0c;因為對方就不…

第五周課程總結實驗報告(三)

實驗三 String類的應用 一、實驗目的 &#xff08;1&#xff09; 掌握類String類的使用&#xff1b; &#xff08;2&#xff09; 學會使用JDK幫助文檔&#xff1b; 二、實驗內容 1.已知字符串&#xff1a;"this is a test of java".按要求執行以下操作&#xff1a;&a…

MMKV集成與原理,趕緊學起來

開頭 Web前端開發基礎知識學習路線分享&#xff0c;前端開發入門學習三大基礎&#xff1a;HTML、CSS、JavaScript。除此之外還要學習數據可視化、Vue、React、Angular相關框架&#xff0c;熟練運用框架提升開發效率&#xff0c;提升穩定性。 [外鏈圖片轉存失敗,源站可能有防盜…

MMKV集成與原理,輕松拿下offer

從事前端開發工作差不多3年了&#xff0c;自己也從一個什么都不懂的小白積累了一定的理論和實踐經驗&#xff0c;并且自己也對這3年來的學習實踐歷程有一個梳理&#xff0c;以供后面來細細回憶品味。 1、為什么選擇學習前端開發&#xff1f; 你可能是因為興趣&#xff0c;完成…

React面試題總結,一文說清!

前言 JavaScript是面向 Web 的編程語言&#xff0c;獲得了所有網頁瀏覽器的支持&#xff0c;是目前使用最廣泛的腳本編程語言之一&#xff0c;也是網頁設計和 Web 應用必須掌握的基本工具。 JavaScript主要用途 嵌入動態文本與HTML頁面對瀏覽器時間做出相應讀寫HTML元素在數…

React面試題總結,含愛奇藝,小米,騰訊,阿里

前言 校招 -1 年 這個階段還屬于成長期&#xff0c;更需要看重的是你的基礎和熱情。對于 JS 基礎&#xff0c;計算機基礎&#xff0c;網絡通信&#xff0c;算法等部分的要求會相對高一些。畢竟這個階段比較難考察你的業務項目中的沉淀&#xff0c;所以只能從基礎部分入手考察。…

React面試題總結,就是這么簡單

前言 昨天有幸去字節面試了&#xff0c;順便拿到了offer&#xff0c;把還記得的東西寫下來&#xff0c;供大家參考一下。 計算機網絡篇 HTTP HTTP 報文結構是怎樣的&#xff1f;HTTP有哪些請求方法&#xff1f;GET 和 POST 有什么區別&#xff1f;如何理解 URI&#xff1f;如…

CSS清除默認樣式,成功入職騰訊

前言 又逢金三銀四&#xff0c;拿到大廠的offer一直是程序員朋友的一個目標&#xff0c;我是如何拿到大廠offer的呢&#xff0c;今天給大家分享我拿到大廠offer的利器&#xff0c;前端核心知識面試寶典&#xff0c;內容囊括Html、CSS、Javascript、Vue、HTTP、瀏覽器面試題\數…

CSS清除默認樣式,技術詳細介紹

前言 JavaScript是面向 Web 的編程語言&#xff0c;獲得了所有網頁瀏覽器的支持&#xff0c;是目前使用最廣泛的腳本編程語言之一&#xff0c;也是網頁設計和 Web 應用必須掌握的基本工具。 JavaScript主要用途 嵌入動態文本與HTML頁面對瀏覽器時間做出相應讀寫HTML元素在數…

CSS清除默認樣式,看完這篇徹底明白了

前端的興起 前端真正興起和開始頻繁出現在大家的視線里&#xff0c;大概是在十年前。彼時的 Web 開發基本是由后端主導&#xff0c;前端能做的只是校驗一下數據、操作一下 DOM。&#xff08;其中數據檢驗是 JS 產生的根本原因&#xff1a;當時網絡太慢&#xff0c;在服務端檢驗…

合并兩個鏈表,去掉重復元素

最近在學習機器學習的相關算法&#xff0c;寫到DbScan算法發現在簇擴展時用到兩個鄰域中的點會重合&#xff0c;于是嘗試了合并兩個鏈表的兩個算法。 最初用到這個方法&#xff0c;認為它簡單易用。思路是定義一個鏈表存放合并后的鏈表list&#xff0c;首先往該鏈表中加入a鏈表…