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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

(Java多线程)线程安全问题

發布時間:2025/3/20 java 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (Java多线程)线程安全问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 線程安全
      • 定義
      • 售票模擬案例
      • 注意
    • 線程同步
      • 同步代碼塊
      • 同步方法
      • Lock鎖

線程安全

定義

  • 如果有多個線程在同時運行,而這些線程可能會同時運行這段代碼。程序每次運行結果和單線程運行的結果是一樣的,而且其他變量的值也和預期的是一樣的,就是線程安全的。

售票模擬案例

  • 電影院要賣票,假設本次電影的電影票共100張。
  • 模擬電影院的售票窗口,實現多個售票窗口同時出售電影票(多個窗口一起賣這100張電影票)
  • 窗口采用線程對象模擬,票采用Runnable接口模擬
  • 模擬票

    public class Ticket implements Runnable{//設置初始票量100private int ticket=100;/*賣票*/@Overridepublic void run() {while (true){if (ticket>0) {//有余票try {Thread.sleep(10);//模擬出票時間} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在賣:" + ticket );ticket--;}else {break;}}} }

    模擬售票窗口

    public class Demo04Ticket {public static void main(String[] args) {//創建線程任務對象Ticket ticket = new Ticket();//創建三個線程Thread t1 = new Thread(ticket,"窗口1");Thread t2 = new Thread(ticket,"窗口2");Thread t3 = new Thread(ticket,"窗口3");//同時賣票t1.start();t2.start();t3.start();} }

    結果:

    發現程序出現了問題:

  • 相同的票數,比如1這張票被賣了2次。
  • 不存在的票,比如-1這張票是不存在的。
  • 幾個(窗口)線程的票數不同步了,這種問題就稱為線程不安全

    注意

    線程安全問題都是由全局變量及靜態變量引起的。若每個線程中對全局變量、靜態變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步 ,否則的話就可能影響線程安全。

    線程同步

    • 當我們使用多個線程訪問同-資源的時候,且多個線程中對資源有寫的操作,就容易出現線程安全問題。
    • 要解決上述多線程并發訪問一一個資源的安全性問題:也就是解決重復票與不存在票問題,Java中提供了同步機制(synchronized)來解決。

    窗口1線程進入操作的時候,窗口2和窗口3線程只能在外等著,窗口1操作結束,窗口1和窗口2和窗口3才有機會進入代碼去執行。
    也就是說在某個線程修改共享資源的時候,其他線程不能修改該資源,等待修改完畢同步之后,才能去搶奪CPU資源,完成對應的操作,保證了數據的同步性,解決了線程不安全的現象。

    完成同步操作的三個方法:

  • 同步代碼塊
  • 同步方法
  • 鎖機制
  • 同步代碼塊

    • 同步代碼塊: synchronized關鍵字可以用于方法的某個區塊中,表示只對這個區塊的資源實行互斥訪問。

    格式:

    synchronized(同步鎖){需要同步操作的代碼 }

    同步鎖:

  • 鎖對象可以是任意類型
  • 多個線程對象要使用同一把鎖
  • 注意:在任何時候,最多允許一個線程擁有同步鎖,誰拿到鎖誰就能進入代碼塊,其他線程只能在外面等待(BLOCKED)。

    使用同步代碼塊解決上述代碼:

    public class Ticket implements Runnable{//設置初始票量100private int ticket=100;//創建鎖對象Object lock = new Object();/*賣票*/@Overridepublic void run() {while (true) {//同步代碼塊synchronized (lock) {if (ticket > 0) {//有余票try {Thread.sleep(100);//模擬出票時間} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在賣" + ticket+"號票");ticket--;} else {break;}}}} }


    使用同步代碼快之后,線程安全問題就解決了。

    同步方法

    • 同步方法:使用synchronized修飾的方法,就叫做同步方法,保證A線程執行該方法的時候,其他線程只能在方法外等待。

    格式:

    public synchronized void method(){可能會產生線程安全問題的代碼 }

    對于非static方法,同步鎖就是this.
    對于static方法,我們使用當前方法所在類的字節碼對象(類名.class)。

    上述代碼使用同步方法示例:

    public class Ticket implements Runnable{//設置初始票量100private int ticket=100;/*賣票*/@Overridepublic void run() {while (true) {payTicket();}}//同步方法private synchronized void payTicket() {if (ticket > 0) {//有余票try {Thread.sleep(100);//模擬出票時間} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在賣" + ticket+"號票");ticket--;}} }

    Lock鎖

    java.util.locks.lock機制提供了比synchronized代碼塊和synchronized方法更廣泛的鎖定操作,同步代碼快和同步方法具有的功能Lock都有,除此之外更強大,更體現面向對象。
    Lock鎖也稱同步鎖,加鎖與釋放鎖方法化了,如下:

    • public void lock:加同步鎖
    • public void unlock:釋放同步鎖

    使用方法如下:

    public class Ticket implements Runnable{//設置初始票量100private int ticket=100;//創建鎖對象Lock lock = new ReentrantLock();/*賣票*/@Overridepublic void run() {while (true){//獲取鎖lock.lock();if (ticket>0) {//有余票try {Thread.sleep(10);//模擬出票時間System.out.println(Thread.currentThread().getName() + "正在賣:" + ticket );ticket--;} catch (InterruptedException e) {e.printStackTrace();}finally {lock.unlock();//無論是否執行成功,都釋放鎖}}else {break;}}} }

    總結

    以上是生活随笔為你收集整理的(Java多线程)线程安全问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。