一起學JAVA——java多線程(其二)

2021-01-06 程龍快序

上一篇文章我們主要介紹了java多線程中的一些核心概念。今天我繼續介紹線程中的其他知識。

線程同步互斥

多個線程同時訪問或操作同一資源時,很容易出現數據前後不一致的問題。請看下面的例子:

男孩拿著存摺子去銀行取錢,女孩拿著男孩的銀行卡去西單百貨瘋狂購物男孩走到櫃檯前詢問帳戶餘額,銀行的業務員小姐告訴他:"您還有10000元!"。

女孩看上了一件時髦的衣裳,準備買下。

男孩在思考要取多少錢呢?

女孩到收銀臺準備刷卡消費,收銀臺刷卡機讀取銀行卡餘額為10000元,女孩買衣服刷卡消費5000元。消費清單列印出來,消費:5000元 餘額:5000元。女孩離開商場。

男孩思考了1秒,男孩決定取5000元。銀行的業務員小姐為男孩辦理相關業務手續交易完成銀行的業務員小姐告訴男孩:"您的餘額為5000元",男孩離開銀行。

男孩帳戶中一共有10000元,男孩拿著存摺從銀行取走5000元,女孩拿著男孩的銀行卡購物刷卡消費5000元,最後男孩的帳戶裡卻還剩5000元。顯然這是不正確的,但是為什麼會發生這樣的情況呢?

我們可以這樣分析:男孩可以看作是一條線程,女孩也可以看作是一條線程,在同一時刻,兩個線程都操作了同一個資源,那就是男孩的帳戶。男孩從查看帳戶餘額到取走現金應該被看作是個原子性操作,是不可再分的,然而當男孩查看完餘額正思考取多少錢的時候,女孩購物消費了5000元,也就是說女孩這條線程打斷了男孩這條線程所要執行的任務。所以男孩剛查看完的餘額10000元就不正確了,最終導致帳戶中少減了5000元。

為了避免這樣的事情發生,我們要保證線程同步互斥,所謂同步互斥就是:並發執行的多個線程在某一時間內只允許一個線程在執行以訪問共享數據。

Java中線程互斥的實現機制

由多線程帶來的性能改善是以可靠性為代價的,所以編程出線程安全的類代碼是十分必要的。當多個線程可以訪問共享資源(調用單個對象的屬性和方法,對數據進行讀、寫、修改、刪除等操作)時,應保證同時只有一個線程訪問共享數據,Java對此提出了有效的解決方案—同步鎖。任何線程要進入同步互斥方法(訪問共享資源的方法或代碼段)時,就必須得到這個共享資源對象的鎖,線程進入同步互斥方法後其它線程則不能再進入同步互斥方法,直到擁有共享資源對象鎖的線程執行完同步互斥方法釋放了鎖,下一個線程才能進入同步互斥方法被執行。

Java的這一線程互斥的實現機制可以用一個最通俗的比方來說明:比如公共衛生間就是一個共享資源,每個人都可以使用,但又不能同時使用,所以衛生間裡有一把鎖。一個人進去了,會把門鎖上,其他人就不能進去。當Ta出來的時候,要打開鎖,下一個人才能繼續使用。

利用Synchronized關鍵字用於修飾同步互斥方法

由於synchronized 塊可以針對任意的代碼塊,且可任意指定上鎖的對象,因此靈活性較高。但要注意:

synchronized可以用來限定一個方法或一小段語句或整個類(該類中的所有方法都是synchronized方法)將訪問共享數據的代碼設計為synchronized方法由於可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以只需針對方法提出一套同步鎖定機制。通過synchronized 方法來控制對類中的成員變量(共享數據)的訪問。編寫線程安全的代碼會使系統的總體效率會降低,要適量使用只有某一個線程的synchronized方法執行完後其它線程的synchronized方法才能被執行。當前時間,只有一個線程訪問被鎖定的代碼段,但不能保證其他線程去訪問其他沒有被鎖定的代碼段。因此所有對共享資源進行操作的代碼段都應該加鎖。對資料庫操作時,修改數據的線程要加鎖,而讀數據的線程可以不加鎖高效利用線程-線程池

線程池的好處在於:

(1)重用存在的線程,減少對象創建、消亡的開銷,性能佳。

(2)可有效控制最大並發線程數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。

(3)提供定時執行、定期執行、單線程、並發數控制等功能。

精品推薦:

一起學JAVA——常用類

一起學JAVA——異常處理

一起學JAVA——面向對象(三)

編程技術筆記——Docker試用

相關焦點

  • Java 多線程的創建方式
    java Vs OS線程 在Hotspot JVM中,Java線程和本機作業系統(即OS)線程之間存在直接映射,在為Java線程準備狀態(包括線程本地存儲,緩衝區分配,創建同步對象,堆棧和程序計數器)之後,將創建本機OS線程.
  • 一起學JAVA——JVM工作原理
    JVM的生命周期1、JVM實例對應了一個獨立運行的java程序它是進程級別啟動。啟動一個Java程序時,一個JVM實例就產生了,任何一個擁有public static void main(String[] args)函數的class都可以作為JVM實例運行的起點運行。main()作為該程序初始線程的起點,任何其他線程均由該線程啟動。
  • JAVA多線程-Semaphore
    >如果用semaphore用於線程間傳遞信號,典型的用法是一個線程調用acquire(),另一個線程調用release()。如果第一個線程阻塞了在等待許可證,當許可證被釋放時,第二個線程檢查許可證,實際可能在第一個線程之前獲取許可證。
  • JAVA多線程 集合同步
    多線程操作ListpublicclassArrayListSynchronization {publicstaticvoidmain(String[] args) {finalList<Integer> arrayList = new ArrayList<Integer>();finalList<Integer>
  • 萬字圖解Java多線程,不信你學不會
    前言java多線程我個人覺得是javaSe中最難的一部分,我以前也是感覺學會了,但是真正有多線程的需求卻不知道怎麼下手,實際上還是對多線程這塊知識了解不深刻,不知道多線程api的應用場景,不知道多線程的運行流程等等,本篇文章將使用實例+圖解+源碼的方式來解析java多線程。
  • Java多線程模式-immutable模式
    場景immutable的意思是「不可變」設計一個類,實例的內部狀態不會發生變更,不用使用鎖機制,線程安全,下面用代碼證實這一點寫線程類import java.util.List;​public class WriteThread extends Thread{​    private final List<String> list;​    public
  • 一起學JAVA——修飾符
    java修飾符的作用就是對類或類成員進行修飾或限制。訪問修飾符訪問修飾符作用是控制類成員的可見度。抽象方法的聲明以分號結尾,例如:public abstract sample();synchronized 修飾符synchronized 關鍵字聲明的方法同一時間只能被一個線程訪問。synchronized 修飾符可以應用於四個訪問修飾符。
  • Java多線程同步的五種方法
    閒話不多說,進入正題。二、為什麼要線程同步因為當我們有多個線程要同時訪問一個變量或對象時,如果這些線程中既有讀又有寫操作時,就會導致變量值或對象的狀態出現混亂,從而導致程序異常。舉個例子,如果一個銀行帳戶同時被兩個線程操作,一個取100塊,一個存錢100塊。假設帳戶原本有0塊,如果取錢線程和存錢線程同時發生,會出現什麼結果呢?
  • 深度剖析——Java多線程
    注意:很多多線程是模擬出來的,真正的多線程是指多個cpu,即多核。如伺服器。;import java.io.IOException;import java.net.URL;/** * 練習Thread,實現多線程同步下載圖片 */public class TestThread2 extends Thread{ private String url;//網絡圖片地址 private String name;//保存文件名 public TestThread2
  • JAVA多線程-Exchanger
    java.util.concurrent.exchanger類代表了兩個線程在一個集合點可以交互數據。下面描述了一下機制: 兩個線程通過Exchanger 正在交換對象數據 執行結果:Thread-0 exchanged A for BThread-1 exchanged B for A 參考翻譯:http://tutorials.jenkov.com/java-util-concurrent
  • 一起學JAVA——常用類
    java提供了很多已經封裝好的類供開發者使用,掌握一些常用類可以大大提高開發效率。Object類Object類被成為超類、根類、頂級父類或上帝類。因為,Object類是所有類的父類,除Object本身外,所有java類都必須直接或間接的繼承java.lang.Object類。
  • java多線程之 Fork/Join框架
    ForkJoinTask 接口的實現類: RecursiveTask 有返回值 RecursiveAction 無返回值demo:import java.util.ArrayList;import java.util.List;import
  • 開發崗位這麼多,為什麼選Java?你學Java了嗎-開課吧
    軟體開發可以使用的語法是非常多,但是為什麼Java被廣泛的使用呢?其他程式語言與Java相比,Java語法相對簡單,並且是很多計算機語言的基礎。提到C++語言,很多人發現在使用過程中最容易出現的錯誤就是內存管理,而java有自動垃圾回收器,不用擔心內存。
  • Java學習(十三): 了解多線程
    多線程介紹多線程執行是Java平臺的一個本質特性。每一個應用程式有至少一個線程(或者如果計算系統線程的話,如內存管理和信號處理,則是多個)。但是從應用程式程式設計師的角度,啟動的只有一個線程,稱為主線程(main thread)。
  • 圖解Java多線程
    圖解Java多線程筆記:http://tutorials.jenkov.com/java-concurrency/java-memory-model.htmlJava內存模型(JMM)定義了:how and when different threads can seevalues written to
  • 萬字圖解Java多線程
    前言java多線程我個人覺得是javaSe中最難的一部分,我以前也是感覺學會了,但是真正有多線程的需求卻不知道怎麼下手,實際上還是對多線程這塊知識了解不深刻,不知道多線程api的應用場景,不知道多線程的運行流程等等,本篇文章將使用實例+圖解+源碼的方式來解析java多線程。
  • 一起學JAVA——Java語法基礎
    關鍵字(51個):其實就是java語言賦予了特殊含義的單詞。package, private, protected, public, return, short, static, strictfp, super, switch, synchronized, this, throw, throws, transient, try, void, volatile, while保留字(14個):其實就是java
  • JAVA多線程-CountDownLatch
    CountDownLatchjava.util.concurrent.CountDownLatch是一個並發構造允許一個或者多個線程等待給定的一組操作完成。CountDownLatch初始化時設置了一個給定的值,當調用 countDown()方法時這個值會遞減, 當這個只為0的時候將喚醒眾多調用 await() 方法線程中的一個線程,調用await() 方法的線程將一直阻塞直到count為0.
  • 一起學JAVA——數據類型
    上一篇我們提到過,java是強數據類型語言,所有在定義變量和常量時必須指定數據類型。java到底支持哪些數據類型呢?java的設計者已經考慮到這個問題了!java提供了兩個特殊的類:BigInteger和BigDecimal。從名字上就可以看出來他們可以存儲很大的數。他支持多大的數呢?要多大就有多大,只要你能寫出來的他都可以存儲!由於他的存儲結構和基本數據不一樣,基本數據類型是按位存儲的,而他們是用字符串來存儲數據的,所以理論上可以存儲無窮大的數。
  • 好程式設計師Java培訓分享Java多線程常見面試問題
    好程式設計師Java培訓分享Java多線程常見面試問題,本篇文章給想要參加Java培訓或者是自學Java準備面試的小夥伴講解一下Java面試中多線程常見問題,希望可以幫助小夥伴順利高薪就業。非常簡單和專業的線程面試問題,但是如果他問你怎樣分析它,就會很棘手。  3、你在多線程環境中遇到的共同的問題是什麼?你是怎麼解決它的?  多線程和並發程序中常遇到的有Memory-interface、競爭條件、死鎖、活鎖和飢餓。問題是沒有止境的,如果你弄錯了,將很難發現和調試。這是大多數基於面試的,而不是基於實際應用的Java線程問題。