多線程_基本操作

来源:https://www.cnblogs.com/fjfsu/archive/2018/03/22/J_Feng.html
-Advertisement-
Play Games

什麼是多線程: 進程:正在運行的程式,QQ 360 ...... 線程:就是進程中一條執行程式的執行路徑,一個程式至少有一條執行路徑。(360中的殺毒 電腦體檢 電腦清理 同時運行的話就需要開啟多條路徑) 每個線程都有自己需要運行的內容,而這些內容可以稱為線程要執行的任務。 開啟多線程是為了同時運行 ...


什麼是多線程:

  進程:正在運行的程式,QQ 360 ......

       線程:就是進程中一條執行程式的執行路徑,一個程式至少有一條執行路徑。(360中的殺毒 電腦體檢 電腦清理 同時運行的話就需要開啟多條路徑)

  每個線程都有自己需要運行的內容,而這些內容可以稱為線程要執行的任務。

  開啟多線程是為了同時運行多部分代碼。

  好處:解決了多部分需要同時運行的問題

  弊端:如果線程過多,會導致效率很低(因為程式的執行都是CPU做著隨機 快速切換來完成的)

  JVM在啟動時,就有著多個線程啟動

  在多線程運行過程中,如有線程拋出了異常,那麼該線程會停止運行(出棧),但是並不影響其他線程的正常運行。

線程的四種狀態:

創建線程:

  方法一:繼承Thread類

  方法二:實現Runnable介面

  分析:創建線程的目的是為了開闢一條執行路徑,讓線程去運行指定的代碼(執行路徑的任務),實現和其他線程同時執行任務。

     JVM創建的主線程任務都定義在了mian方法中;自定義的線程任務將要封裝在Thread類的run方法中。

 

  方法一的步驟:1:繼承Thread類   2:重寫run方法(封裝任務)  3:實例化Thread類的子類對象   4:調用start方法開啟線程(這個方法會調用run方法來執行任務)

 1 class Text{
 2     public static void main(String[] args) {
 3         aThread Dome=new aThread();
 4         Dome.start();
 5         System.out.println(Thread.currentThread().getName());
 6     }
 7 }
 8 class aThread extends Thread{
 9     public void run(){
10         System.out.println(Thread.currentThread().getName());
11     }
12 }

currentThread()是一個靜態方法,它返回的是當前正在運行線程的這個對象,然後調用getName方法返回這個線程的名字;

名字是Thread-編號(從0開始),主函數的名字就是main。

Thread類中有個接收String類型參數的構造方法,我們傳入的數據可以自定義線程的名字。如下代碼:

1 class aThread implements Runnable{
2     aThread(String a){
3         super(a);
4     }
5     public void run(){
6         System.out.println(this.getName());
7     }
8 }

 

  如果一個子類已經有了父類,但是它需要開啟多線程來執行任務,那麼就要用到Runnable這個介面來擴展該子類的功能(避免了java的單繼承局限性)

  Runnable這個介面只有一個run一個抽象方法,所以Runnable介面的出現僅僅是為了用run封裝任務而存在的;而且Thread類也實現了Runnable介面

  

  方法二的步驟:1:實現Runnable介面 2:重寫run方法(封裝任務) 3:創建Thread線程a  創建Runnable子類對象t  

         4:將t作為參數傳遞給a(Thread有個構造方法是用來接收Runnable類型參數的;因為任務都封裝在了Runnbale子類的run方法中,

           在開啟線程的時候就要明確線程的任務,否則Thread會調用自己的run方法,Runnbale子類中的任務將永遠不會被執行到)

         5:開啟線程(start)

 1 class Text{
 2     public static void main(String[] args) {
 3         aThread t=new aThread();
 4         Thread a=new Thread(t);
 5         a.start();
 6         System.out.println(Thread.currentThread().getName());
 7     }
 8 }
 9 class aThread implements Runnable{
10     
11     public void run(){
12         System.out.println(Thread.currentThread().getName());
13     }
14 }

  實現Runnable介面的好處:1.將任務從Thread子類中分離出來,進行單獨的封裝;按照面向對象的思想將任務封裝成了對象

               2.避免了JAVA單繼承的局限性

 

多線程安全問題:

  原因: 1.多個線程操作共用數據

             2.操作共用數據的代碼有多條

                  當一個線程在執行共用數據的多條代碼時,有其他的線程參與進來,就會導致線程安全問題的產生。

  例:

 1 class Text{
 2     public static void main(String[] args) {
 3         aThread t=new aThread();
 4         Thread a=new Thread(t);
 5         Thread a1=new Thread(t);
 6         Thread a2=new Thread(t);
 7         Thread a3=new Thread(t);
 8         a.start();
 9         a1.start();
10         a2.start();
11         a3.start();
12     }
13 }
14 class aThread implements Runnable{
15     private int mun=100;
16     public void run(){
17         while(mun>0){
18             try{Thread.sleep(5);}catch(InterruptedException e){}
19             /*為了能夠看得清楚,讓線程凍結,sleep會拋出異常由於Runnable介面並沒有拋出異常
20             ,所以其子類也不能拋,只能try catch去捕捉異常。*/
21             System.out.println(Thread.currentThread().getName()+"....."+mun--);
22         }/*運行的結果中會出項這樣的情況Thread-3.....42  Thread-0.....42
23                 (如果是賣票的話我們可以理解為這兩個線程都賣了42號這個票,這是不允許的)*/
24     }
25 }

解決問題:

  思路:當有線程操作共用數據的代碼塊時,不允許其他線程參與進來,即同步(簡單說就是給共用數據的代碼塊安個鎖,線程進來的時候都要判斷一下是不是有別的線程正在操作共用數據代碼塊)

  同步的好處:解決了安全問題

  同步的弊端:相對而言效率降低了(因為每次都需要判斷鎖)

  註意:這幾個線程一定要使用同一個鎖

  方法一:同步代碼塊

  方法二:同步函數

  關鍵字:synchronized

  

  實現方法一(同步代碼塊):

 1 class Text{
 2     public static void main(String[] args) {
 3         aThread t=new aThread();
 4         Thread a=new Thread(t);
 5         Thread a1=new Thread(t);
 6         Thread a2=new Thread(t);
 7         Thread a3=new Thread(t);
 8         a.start();
 9         a1.start();
10         a2.start();
11         a3.start();
12     }
13 }
14 class aThread implements Runnable{
15     private int mun=100;
16     private Object obj=new Object();
17     public void run(){
18         while(mun>0){
19             synchronized(obj){
20                 if(mun<=0)return;
21                 try{Thread.sleep(5);}catch(InterruptedException e){}
22             System.out.println(Thread.currentThread().getName()+"....."+mun--);
23             }    
24         }
25     }
26 }

同步代碼塊的鎖是可以自定義的,這裡的鎖我自定義的是Obiect類的對象obj

 

  實現方法二(同步函數):

 1 class Text{
 2     public static void main(String[] args) {
 3         aThread t=new aThread();
 4         Thread a=new Thread(t);
 5         Thread a1=new Thread(t);
 6         Thread a2=new Thread(t);
 7         Thread a3=new Thread(t);
 8         a.start();
 9         a1.start();
10         a2.start();
11         a3.start();
12     }
13 }
14 class aThread implements Runnable{
15     private int mun=100;
16     17     public void run(){
18         while(mun>0)
19         show();
20     }
21     public synchronized void show(){
22             if(mun<=0)return;
23             try{Thread.sleep(5);}catch(InterruptedException e){}
24             System.out.println(Thread.currentThread().getName()+"....."+mun--);    
25     }
26 }

同步函數的鎖是固定的this

靜態同步函數的鎖,是這個函數所屬的位元組碼對象(class文件)

 

  建議使用同步代碼塊

死鎖:

  同步的嵌套,有兩把鎖,都拿著對方的鎖,導致代碼無法繼續進行下去。

 1 class Text{
 2     public static void main(String[] args) {
 3         aThread a=new aThread(true);
 4         aThread a1=new aThread(false);
 5         Thread t=new Thread(a);
 6         Thread t1=new Thread(a1);
 7         t.start();
 8         t1.start();
 9     }
10 }
11 class aThread implements Runnable{
12     private boolean flag;
13     aThread(boolean flag){
14         this.flag=flag;
15     }
16     public void run(){
17         if(flag){
18             synchronized(suo.suo1){
19                 System.out.println("我是if鎖1");
20                 synchronized(suo.suo2){
21                     System.out.println("我是if鎖2");    
22                 }
23             }
24         }else{
25             synchronized(suo.suo2){
26                 System.out.println("我是elsef鎖2");
27                 synchronized(suo.suo1){
28                     System.out.println("我是else鎖1");    
29                 }
30             }
31         }
32     }    
33 }
34 class suo{
35     public static final Object suo1=new Object();
36     public static final Object suo2=new Object();
37 }

懶漢式在多線程中的應用:

  因為懶漢式並沒有直接實例化對象,線上程0判斷了if語句後進入臨時阻塞狀態,線程1也進入了進來,這就導致了實例化不唯一

實例化不唯一問題的示例代碼:

 1 public class Text1 {
 2 
 3     public static void main(String[] args) {
 4         Ab a=new Ab();
 5         Ab b=new Ab();
 6         a.start();
 7         b.start();
 8         try{Thread.sleep(10);}catch(InterruptedException e){}
 9         System.out.print(a.get()==b.get());
10     }
11 }
12 class Single{
13     private static Single a=null;
14     private Single(){
15     }
16     static Single  getSingle(){
17         if(a==null){
18             try{Thread.sleep(10);}catch(InterruptedException e){}
19             a=new Single();
20         }
21         return  a;
22     }
23 }
24 class Ab extends Thread{
25     private Single a;
26     public void run(){
27         a=Single.getSingle();
28     }
29     Single get(){
30         return a;
31     }
32 }

多試幾次輸出的結果就會出現false

  

  解決問題(同步)(餓漢式代碼應該如下修改):

 1 class Single{
 2     private static Single a=null;
 3     private Single(){
 4     }
 5     static Single  getSingle(){
 6         if(a==null){
 7             synchronized (Single.class){
 8                 if(a==null){
 9                     a=new Single();
10                }
11             }
12         }
13         return  a;
14     }
15 }

註意:在原有的餓漢式代碼中多加了一個if判斷,是為了提高效率,不然的還線程總是會去判斷鎖,效率下降,這也是不時用同步函數的原因。

   加了同步,是為瞭解決安全問題。

所以在開發的時候還是使用餓漢式好

 

 

 

 

 

 

 

 

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如果你是一個人在自學前端開發,或者是對前端開發有比較濃厚的興趣正想踏入前端領域,亦或者是已經在工作了,難免會遇到問題,與其一個人冥思苦想,抓耳撓腮,不如將問題拋出來,小伙伴們的見解會給你帶來新的收穫。當然也期待你可以貢獻自己的知識,幫助其他小伙伴,相信你不是一個人在前端的路上戰鬥,期待你的加入,大家 ...
  • 因為object沒有某個方法,但是別的對象有,可以藉助apply或call像別的對象借方法來操作。 貓吃魚,狗吃肉,奧特曼打小怪獸。 有天狗想吃魚了 貓.吃魚.call(狗,魚) 狗就吃到魚了 貓成精了,想打怪獸 奧特曼.打小怪獸.call(貓,小怪獸) call需要把參數按順序傳遞進去,而appl ...
  • Karma 官方介紹 A simple tool that allows you to execute JavaScript code in multiple real browsers. 即一個允許你在多個真實瀏覽器中執行js代碼的簡單工具。 使用了karma之後,我們之前為了Enzyme的mou ...
  • 從今天(2018-03-21)開始,我將淺談下設計模式,這個話題肯定很多人談過。由於我知識廣度和深度均有不足,如有不合理的地方請多多包涵。在此只希望能幫助更多同行的小白,藉此本人感覺很慰藉。當談完設計模式後,我將開源一個完全自己寫的DAL層,包括orm,連接池,線程,事務,MSIL,設計思路等。閑話 ...
  • 這裡只有乾巴巴的貨物 底層實現,我希望您理解記憶體地址,通多DeBug調試可以查看編譯器如何實現定址操作。可以幫助你理解為什麼是這樣的 ...
  • 《代碼大全2》第一、二、三章 隱喻思維在西方是一個熱門的話題,隱喻的認知功能在各個學科正受到越來越多的重視,依照我的理解,其實就是以眾所周知或者理解主體熟悉的事物為符號去將新事物、新概念具象化,與打比方的認知方式有同工異曲之妙。在《代碼大全2》第二章,作者Steve McConnell主要列舉了4種 ...
  • 讀了微軟 Azure 總結的雲計算設計模式系列文章,覺得很受啟發,遂將這個系列翻譯出來如下。 雲計算模型 這些設計模式對於在雲上構建高可用性,伸縮性,安全的應用程式很有用。 每個模式都描述了該模式試圖解決的問題,在使用該模式時應考慮的問題,以及一個基於微軟 Azure 雲的例子。大多數的模式中包含了 ...
  • 對於多數從其他編程語言轉入Python的來說,或多或少會有些不習慣。如果沿用其他編程語言的語法來寫Python代碼,那麼碰壁是不可避免的了。 本文是基於我看了兩個小時的官方文檔(Python 2.7 : https://docs.python.org/2/tutorial/index.html , ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...