一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java中關于線程安全的三種解決方式

Java中關于線程安全的三種解決方式

2021-12-30 13:29威斯布魯克.猩猩 Java教程

這篇文章主要介紹了Java中關于線程安全的三種解決方式,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

三個窗口賣票的例子解決線程安全問題

  • 問題:買票過程中,出現了重票、錯票-->出現了線程的安全問題
  • 問題出現的原因:當某個線程操作車票的過程中,尚未操作完成時,其他線程參與進來,也操作車票
  • 如何解決:當一個線程a在操作ticket的時候,其他線程不能參與進來,知道線程a操作完ticket時,其他線程才可以開始操作ticket,這種情況即使線程a出現了阻塞,也不能被改變
  • 在Java中,我們通過同步機制,來解決線程的安全問題。(線程安全問題的前提:有共享數據)

方式一:同步代碼塊

synchronized(同步監視器){
//需要被同步的代碼(或操作共享數據的代碼)
}

說明:

1.操作共享數據的代碼,即為需要被同步的代碼(不能包含代碼多了(變成單線程會效率低,也有可能會出錯),也不能包含代碼少了(沒包的會阻塞))

2.共享數據:多個線程共同操作的變量。比如:ticket就是共享數據

3.同步監視器,俗稱:鎖。任何一個類的對象,都可以充當鎖。

要求:多個線程必須要共用同一把鎖。(特別注意!!!!!)
補充:在實現Runnable接口創建多線程的方式中,我們可以考慮使用(具體問題具體分析)this充當同步監視器

class window1 implements Runnable{
    private int ticket = 100;
//    Object obj = new Object();
    @Override
    public void run() {
        while (true){
            synchronized (this) {//此時的this:唯一的Window1的對象
//            synchronized(obj) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "賣票,票號為:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}
public class WindowTest1 {
    public static void main(String[] args) {
        window1 w = new window1();//只造了一個對象,所以100張票共享
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("線程1");
        t2.setName("線程2");
        t3.setName("線程3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window extends Thread{
    private static int ticket = 100;//三個窗口共享:聲明為static
    private static Object obj = new Object();
    @Override
    public void run() {
        while(true) {
//                synchronized (obj) {
              synchronized (Window.class){//Class clazz = Window.class,Window.class只會加載一次
//              synchronized (this) {//錯誤的方式:this代表著t1,t2,t3三個對象
                        if (ticket > 0) {
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println(getName() + ":賣票,票號為:" + ticket);
                            ticket--;
                        } else {
                            break;
                        }
                    }
                }
        }
    }
public class WindowTest {
    public static void main(String[] args) {
        Window t1 = new Window();
        Window t2 = new Window();
        Window t3 = new Window();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

方式二:同步方法

如果操作共享數據的代碼完整的聲明在一個方法中,我們不妨將此方法聲明同步的。
4.同步的方式,解決了線程的安全問題。---->好處
操作同步代碼時,只能有一個線程參與,其他線程等待。相當于是一個單線程的過程,效率低。--->局限性

關于同步方法的總結:
1.同步方法仍然涉及到同步監視器,只是不需要我們顯式的聲明。
2.非靜態的同步方法,同步監視器是:this
靜態的同步方法,同步監視器是:當前類本身

class window3 implements Runnable{
    private int ticket = 100;
    @Override
    public void run() {
        while (true){
            show();
        }
    }
    public synchronized void show(){//同步監視器:this(未顯示聲明而已)
        if (ticket > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "賣票,票號為:" + ticket);
            ticket--;
        }
    }
}
public class WindowTest3 {
    public static void main(String[] args) {
        window3 w = new window3();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("線程1");
        t2.setName("線程2");
        t3.setName("線程3");
        t1.start();
        t2.start();
        t3.start();
    }
}
class Window4 extends Thread{
    private static int ticket = 100;//三個窗口共享:聲明為static
    @Override
    public void run() {
        while(true){
           show();
        }
    }
    private static synchronized void show() {//同步監視器:Window4.class(類)
//        private synchronized void show() {//同步監視器:t1,t2,t3。此種解決方式是錯誤的
        if(ticket > 0){
            System.out.println(Thread.currentThread().getName() + ":賣票,票號為:" + ticket);
            ticket--;
        }
    }
}
public class WindowTest4 {
    public static void main(String[] args) {
        Window4 t1 = new Window4();
        Window4 t2 = new Window4();
        Window4 t3 = new Window4();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

方式三:Lock鎖---JDK5.0新增

JDK5.0開始,Java提供了更強大的線程同步機制---通過顯式定義同步鎖對象來實現同步,同步鎖使用Lock對象充當。

java.util.concurrent.locks接口是控制多個線程對共享資源進行訪問的工具。鎖提供了對共享資源的獨占訪問,每次只能有一個線程對Lock對象加鎖,線程開始訪問共享資源之前應先獲得Lock對象

ReentrantLock類實現了Lock,它擁有與synchronized相同的并發性和內存語義,在實現線程安全的控制中,比較常用的是ReentrantLock,可以顯式加鎖,釋放鎖。

class Window implements Runnable{
    private int ticket = 100;
    //1.實例化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            try{
                //2.調用鎖定方法:lock()
                lock.lock();
                if(ticket > 0){
                    try {
                        Thread.sleep(100);
                     }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "售票,票號為:" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }  finally{
                //3.調用解鎖方法:unlock();
                lock.unlock();
            }
        }
    }
}
public class LockTest {
    public static void main(String[] args) {
        Window w = new Window();
        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

線程的死鎖問題

1.死鎖的理解:不同的線程分別占用對方需要的同步資源不放棄,都在等待對方放棄自己的需要
的同步資源,就形成了線程的死鎖。
2.說明:
>出現死鎖后,不會出現異常,不會出現提示,只是所有的線程都處于阻塞狀態,無法繼續
>我們使用同步時,要避免出現死鎖

3.解決方法

A.專門的算法、原則 B.盡量減少同步資源的定義 C.盡量避免嵌套同步

public class ThreadTest {
    public static void main(String[] args) {
        StringBuffer s1 = new StringBuffer();
        StringBuffer s2 = new StringBuffer();
        new Thread(){//匿名的方式繼承
            @Override
            public void run() {
               synchronized(s1){
                   s1.append("a");
                   s2.append("1");
                   try {
                       Thread.sleep(100);//增加死鎖出現概率
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   synchronized (s2){
                       s1.append("b");
                       s2.append("2");
                       System.out.println(s1);
                       System.out.println(s2);
                   }
               }
            }
        }.start();
        new Thread(new Runnable(){//匿名的方式實現Runnable接口
            @Override
            public void run() {
                synchronized (s2){
                    s1.append("c");
                    s2.append("3");
                    try {
                        Thread.sleep(100);//增加死鎖出現概率
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (s1){
                        s1.append("d");
                        s2.append("4");
                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }).start();
    }
}

synchronized和Lock的對比

1.Lock是顯示鎖(手動開啟和關閉鎖,別忘記關閉鎖),synchronized是隱式鎖,出了作用域自動釋放

2.Lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖

3.使用Lock鎖,JVM將花費較少的時間來調度線程,性能更好。并且具有更好的拓展性(提供更多的子類)

4.synchronized 與 Lock的異同?

相同:二者都可以解決線程安全問題

不同:synchronized機制在執行完相應的同步代碼以后,自動的釋放同步監視器 Lock需要手動的啟動同步(lock()),同時結束同步也需要手動的實現(unlock())

優先使用順序: Lock ->同步代碼塊(已經進入了方法體,分配了相應資源) ->同步方法(在方法體之外)

Java中關于線程安全的三種解決方式

Java中關于線程安全的三種解決方式

到此這篇關于Java中關于線程安全的三種解決方式的文章就介紹到這了,更多相關Java 線程安全內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/weixin_49329785/article/details/119384519

延伸 · 閱讀

精彩推薦
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
主站蜘蛛池模板: 天堂网在线网站成人午夜网站 | 二次元美女挤奶漫画 | 亚洲人的天堂男人爽爽爽 | 肉性天堂 | 亚洲天堂成人在线观看 | 久久亚洲国产成人影院 | 免费在线电视 | 亚洲天堂视频在线观看 | 热99精品在线 | 全彩孕交漫画福利啪啪吧 | 2021国产精品视频一区 | 校园全黄h全肉细节文 | 4虎影院在线观看 | 日本丰满www色 | 亚洲精品国产A久久久久久 亚洲精品福利一区二区在线观看 | 精品久久香蕉国产线看观看亚洲 | 成人福利免费视频 | 国内精品视频一区二区三区八戒 | 深夜激情网 | 国产在线观看人成激情视频 | 日韩在线一区二区 | 99视频精品全部免费观看 | 秋葵污视频 | 无人影院在线播放视频 | 久久精视频 | 热久久最新 | 国产亚洲精品一区久久 | 精品国产自在在线在线观看 | 手机在线伦理片 | 精品无人区麻豆乱码1区2 | 特黄特色大片免费视频播放 | 美女脱了内裤让男生玩屁股 | 免费国产在线视频 | 国产精品欧美在线观看 | 国产精品九九免费视频 | wc凹凸撒尿间谍女厕hd | 精品国产乱码久久久久久人妻 | 日本午夜大片免费观看视频 | 成人福利在线播放 | 欧美日韩高清不卡一区二区三区 | 青青草成人在线 |