主頁 >  其他 > 多執行緒詳解(二)

多執行緒詳解(二)

2021-12-07 16:12:12 其他

多執行緒

    • 4.4 題外話
  • 5 執行緒的死鎖問題
    • 5.1 概念
      • 5.1.1 死鎖的理解
      • 5.1.2 說明
      • 5.1.3舉例
    • 5.2 解決方法
    • 5.3 演示執行緒的死鎖問題
  • 6.JDK5.0 新增解決執行緒安全問題
    • 6.1 概念
    • 6.2 步驟
    • 6.3 舉例
    • 6.4 synchronized與Lock 的異同?(面試題)
  • 7.執行緒的通信
    • 7.1 執行緒通信的例子
    • 7.2 涉及到三個方法及注意點
      • 7.2.1 方法
      • 7.2.2 注意點:
      • 7.2.3 面試題: sleep() 和 wait() 的異同?
    • 7.3 舉例
  • 8.JDK5.0新增執行緒創建方式
    • 8.1 多執行緒創建,方式三:實作Callable介面
      • 8.1.1 步驟
      • 8.1.2 Callable比Runnable更強大
      • 8.1.3 舉例
    • 8.2 多執行緒創建,方式四:使用執行緒池(開發常用的)
      • 8.2.1 介紹
      • 8.2.2 步驟
      • 8.2.3 好處
      • 8.2.4 舉例
  • 9. 面試題

4.4 題外話

根據多執行緒詳解(一)的同步,
我們可以使用同步機制將單例模式中的懶漢式改寫為執行緒安全的,

舉例:

public class BankTest {  }
class Bank{
    private Bank(){}
    private static Bank instance = null;

    public static Bank getInstance() {
//方式一:在方法上 加 synchronized 效率稍差

//方式二:效率稍差 只要判斷一次同步一次 后面就不用同步了
//解決方案就相當于只有一臺手機 買完人走了 出公告 手機賣完了 不用再進來了
//        synchronized (Bank.class) {
//            if (instance == null){
//                instance = new Bank();
//            }
//            return instance;
//        }

        //方式三:效率更高
        if (instance == null){
            synchronized (Bank.class) {
                if (instance == null){
                    instance = new Bank();
                }
            }
        }
        return instance;//這行就不算操作
    }
}

5 執行緒的死鎖問題

5.1 概念

5.1.1 死鎖的理解

不同的執行緒分別占用對方需要的同步資源不放棄,
都在等待對方放棄自己需要的同步資源,就形成了執行緒的死鎖

5.1.2 說明

1.出現死鎖后,不會出現例外,不會出現提示,
只是所有的執行緒都處于阻塞狀態,無法繼續

2.我們使用同步時,要避免出現死鎖

5.1.3舉例

一人一個筷子,互不相讓,就打起來了,

5.2 解決方法

  1. 專門的演算法、原則
  2. 盡量減少同步資源的定義
  3. 盡量避免嵌套同步

5.3 演示執行緒的死鎖問題

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是鎖
                    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() {
            @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();
    }
}

一個等著拿s2 一個拿著s2等著拿s1 互相僵持

6.JDK5.0 新增解決執行緒安全問題

6.1 概念

解決執行緒安全問題的方式三: Lock鎖 —JDK5.0新增

》通過顯式定義同步鎖物件來實作同步,
》同步鎖使用Lock物件充當,

6.2 步驟

  1. 實體化ReentrantLock
  2. 呼叫鎖定方法lock()
  3. 呼叫解鎖方法:unlock()

6.3 舉例

使用Lock鎖解決實作Runnable介面的執行緒安全問題

import java.util.concurrent.locks.ReentrantLock;

class Window implements Runnable{
    private int ticket = 100;
    //1.實體化ReentrantLock
    private ReentrantLock lock = new ReentrantLock();
    //默認值是false  引數是boolean fair(公平)
    // 設定true 先進先出 一個個執行 不會出現有個執行了下一刻又搶到了
    @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();
    }
}

如果你用的是繼承于Thread類 lock要加個靜態 要用同一個

6.4 synchronized與Lock 的異同?(面試題)

相同:
二者都可以解決執行緒安全問題

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

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

7.執行緒的通信

7.1 執行緒通信的例子

使用兩個執行緒列印1-100,執行緒1,執行緒2交替列印(一個一個互動進入)

7.2 涉及到三個方法及注意點

7.2.1 方法

wait():
一旦執行此方法,當前執行緒就進入阻塞狀態,并釋放同步監視器,
notify():
一旦執行此方法,就會喚醒被wait的一個執行緒,
如果有多個執行緒被wait,就喚醒優先級高的那個,
notifyAll():
一旦執行此方法,就會喚醒所有被wait的執行緒

7.2.2 注意點:

1.wait(), notify(), notifyAll() 三個方法必須使用在同步代碼塊或同步方法中,

2.wait(), notify(), notifyAll() 三個方法的呼叫者必須是同步代碼塊或同步方法中的同步監視器,
否則,會出現IllegaLMonitorStateException例外

3.wait(), notify(), notifyAll() 三個方法是定義在java.lang.Object類中,

7.2.3 面試題: sleep() 和 wait() 的異同?

相同點:
一旦執行方法, 都可以使得當前的執行緒進入阻塞狀態,

不同點:
1)兩個方法宣告的位置不同: Thread類中宣告sleep(),object類中宣告wait()

2)呼叫的要求不同:
sleep()可以在任何需要的場景下呼叫,
wait()必須使用在同步代碼塊或同步方法中

3)關于是否釋放同步監視器:
如果兩個方法都使用在同步代碼塊或同步方法中,sleep()不會釋放鎖,wait() 會釋放鎖,

7.3 舉例

class Number implements Runnable {
    private int number = 1;//共享資料

    @Override
    public void run() {
        while (true){
            synchronized (this) { //this代表number物件
                notify();//執行緒一把執行緒二喚醒 執行緒二把執行緒一喚醒 notifyAll()就是喚醒所有  省略了this
                if (number <= 100) {
                    try {
                        Thread.sleep(10);//sleep 不會釋放鎖
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number++;
                    //使得呼叫如下wait() 方法的執行緒進入阻塞狀態 wait會釋放鎖
                    try {
                        wait();//  省略了this
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }
}
public class CommunicationTest {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);
        t1.setName("執行緒1");
        t2.setName("執行緒2");
        t1.start();
        t2.start();
    }
}

8.JDK5.0新增執行緒創建方式

8.1 多執行緒創建,方式三:實作Callable介面

8.1.1 步驟

Future介面最重要

  1. 創建一個實作Callable的實作類
  2. 實作call方法,將此執行緒需要執行的操作宣告在call()中
  3. 創建Callable介面實作類的物件
  4. 將此Callable介面實作類的物件作為傳遞到FutureTask構造器中,
    創建FutureTask 的物件
  5. 將Future Task的物件作為引數傳遞到Thread類的構造器中,
    創建Thread物件,并呼叫start()
  6. 獲取Callable中call方法的回傳值

8.1.2 Callable比Runnable更強大

如何理解實作Callable介面的方式創建多執行緒
比實作Runnable介面創建多執行緒方式要強大

  1. call()可以有回傳值的
  2. call() 可以拋出例外,被外面的操作捕獲,獲取例外的資訊
  3. Callable是支持泛型的

8.1.3 舉例

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//1.創建一個實作Callable的實作類
class NumThread implements Callable<Integer> {
    //2.實作call方法,將此執行緒需要執行的操作宣告在call()中
    @Override
    public Integer call() throws Exception {//回呼方法
        int sum = 0;
        for (int i = 1 ; i <= 100 ; i++) {
            if (i % 2 == 0){
                System.out.println(i);//分執行緒
                sum += i;
            }
        }
        return sum;
    }
}
public class ThreadNew {
    public static void main(String[] args) {
        //3.創建Callable介面實作類的物件
        NumThread numThread = new NumThread();
        //4.將此Callable介面實作類的物件作為傳遞到FutureTask構造器中,創建FutureTask 的物件
        FutureTask<Integer> futureTask = new FutureTask<>(numThread);
        //5.將Future Task的物件作為引數傳遞到Thread類的構造器中,創建Thread物件,并呼叫start()
        new Thread(futureTask).start();
        try {
            //6.獲取Callable中call方法的回傳值
            //get()回傳值即為FutureTask構造器引數Callable實作類重寫的calL()的回傳值,
            Integer sum = futureTask.get();//調get方法獲取Callable介面實作類的回呼方法
            System.out.println("總和為:" + sum);//主執行緒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

8.2 多執行緒創建,方式四:使用執行緒池(開發常用的)

8.2.1 介紹

背景:
經常創建和銷毀、使用量特別大的資源,比如并發情況下的執行緒,對性能影響很大,

解決方案:
提前創建好多個執行緒,放入執行緒池中,使用時直接獲取,使用完放回池中,
可以避免頻繁創建銷毀、實作重復利用,類似生活中的公共交通工具,

8.2.2 步驟

  1. 提供指定執行緒數量的執行緒池
  2. 執行指定的執行緒的操作,
    需要提供實作Runnable介面 或 Callable介面實作類的物件
  3. 關閉執行緒池

8.2.3 好處

  1. 提高回應速度(減少了創建新執行緒的時間)
  2. 降低資源消耗(重復利用執行緒池中執行緒,不需要每次都創建)
  3. 便于執行緒管理
    corePoolSize:核心池的大小
    maximumPoolSize:最大執行緒數
    keepAliveTime:執行緒沒有任務時最多保持多長時間后會終止

8.2.4 舉例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

class NumberThread implements Runnable {
    @Override
    public void run() {
        for (int i = 1 ; i <= 100 ; i++) {
            if (i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);//分執行緒
            }
        }
    }
}
class NumberThread1 implements Runnable {
    @Override
    public void run() {
        for (int i = 1 ; i <= 100 ; i++) {
            if (i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);//分執行緒
            }
        }
    }
}
public class ThreadPool {
    public static void main(String[] args) {
        //1.提供指定執行緒數量的執行緒池
        ExecutorService service = Executors.newFixedThreadPool(10);//造了個執行緒池
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
       //設定執行緒池的屬性
//        System.out.println(service.getClass());//獲取是哪個類造的
        service1.setCorePoolSize(15);

        //2.執行指定的執行緒的操作,需要提供實作Runnable介面 或 Callable介面實作類的物件
        //執行緒要干什么不知道 所以還是要提供實作 Runnable介面的 實作類
        service.execute(new NumberThread());//適合適用于Runnable
        service.execute(new NumberThread1());//適合適用于Runnable
//       service.submit(Callable callable);//適合適用于Callable

        service.shutdown();//3.關閉執行緒池
    }
}

9. 面試題

一共有幾種多執行緒創建方式? 》 4種

解決執行緒安全問題? 》3種

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/375212.html

標籤:其他

上一篇:【pwnable.kr】Toddler‘s Bottle-[passcode]

下一篇:Barrett And Montgomery of Polynomials

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more