1. 程式人生 > >javase知識點 ----20 (多執行緒)

javase知識點 ----20 (多執行緒)

1、程序:正在執行的程式稱作一個程序。程序負責了記憶體空間的劃分。
   Windows號稱是多工的作業系統,那麼Windows是同時執行多個應用程式嗎?
         從巨集觀角度:Windows確實是在同時執行多個應用程式。
         從微觀角度:cpu是做了一個快速切換執行的動作,由於速度太快,所以我們感覺不到切換而已。
   執行緒:執行緒在一個程序中負責了程式碼執行。
   多執行緒:在一個程序中有多個執行緒同時在執行不同的任務。
2、java中的執行緒:
   疑問?執行緒負責了程式碼的執行,我們之前沒有寫過執行緒,為什麼程式碼可以執行呢?
   答:執行任何一個java程式,jvm在執行的時候都會建立一個主執行緒執行main方法中所有程式碼。

   疑問?一個java應用程式至少有幾個執行緒?
   答:至少有兩個執行緒,一個是主執行緒負責main方法程式碼執行;一個是垃圾回收器執行緒,負責了回收垃圾

3、多執行緒的好處
   1、多執行緒最大好處在於可以同時併發執行多個任務;
   2、多執行緒可以最大限度地減低CPU的閒置時間,從而提高CPU的利用率。

   多執行緒的弊端
   1、增加了cpu負擔
   2、降低了一個程序中執行緒的執行效率
   3、引發了執行緒安全問題
   4、出現了死鎖現象
4、Java建立執行緒的兩種方法:繼承Thread類的方式和實現Runnable介面的方式

 (1)繼承Java.lang.Thread類,並重寫run()方法。
      定義:
      class MyThread extends Thread {     
      //把自定義執行緒的任務程式碼寫在run方法中     
          public void run( ) {         
              /* 覆蓋該方法*/       
       }  }

      呼叫:
      MyThread thread = new MyThread();
      thread.start();

      run():把自定義執行緒的任務程式碼寫在run方法中
      start():啟動執行緒
      getName():返回此執行緒的名稱
  
      疑問:重寫run方法的目的是什麼?
      每個執行緒都有自己的任務程式碼,jvm建立的主執行緒的任務程式碼就是main方法中的所有程式碼,自定義執行緒中任務程式碼就是寫在run方法中,自定義執行緒負責了run方法中所有程式碼。
      
  注意:1、一個執行緒一旦開啟,那麼執行緒就會執行run方法中的程式碼,run方法千萬不能直接呼叫,如果直接呼叫就相當於呼叫了一個普通方法而已,並沒有開啟執行緒。
        2、啟動執行緒,執行緒將等待排程(到底什麼時候被排程,不一定要看當前的作業系統分配資源的情況);排程後,自動呼叫其run方法,run方法是等著被自動呼叫的。
 
(2)實現Java.lang.Runnable介面,並重寫run() 方法;
     定義:
     class MyThread implements Runnable{
         public void run( ) {
              //實現該方法
       }
     }
     呼叫:MyThread t = new MyThread();
           Thread th = new Thread(t);
           th.start();

     static Thread currentThread():返回對當前正在執行的執行緒物件的引用。
     Thread(Runnable target, String name) 分配一個新的 Thread物件,並且賦值執行緒名稱

     注意:Runnable介面的存在主要是為了解決Java中不允許多繼承的問題。

 (3)兩種執行緒建立方式的比較:
    繼承Thread類:
    優勢:Thread類已實現了Runnable介面,故使用更簡單
    劣勢:無法繼承其它父類

    實現Runnable介面:
    優勢:可以繼承其它類
    劣勢:程式設計方式稍微複雜,多寫一行程式碼

5、執行緒狀態:
   建立:新建立了一個執行緒物件。
   可執行:執行緒物件建立後,其他執行緒呼叫了該物件的start()方法。該狀態的執行緒位於可執行執行緒池中,變得可執行,等待獲取cpu的執行權。
   執行:就緒狀態的執行緒獲取了CPU執行權,執行程式程式碼。
    阻塞狀態: 阻塞狀態是執行緒因為某種原因放棄CPU使用權,暫時停止執行。直到執行緒進入就緒狀態,才有機會轉到執行狀態。
    死亡:執行緒執行完它的任務時。

6、Thread類中常用的構造方法
   Thread()    建立一個新的執行緒
   Thread(String name)    建立一個指定名稱的執行緒
   Thread(Runnable target)    利用Runnable物件建立一個執行緒,啟動時將執行該物件的run方法
   Thread(Runnable target, String name)    利用Runnable物件建立一個執行緒,並指定該執行緒的名稱

7、thread類中的常用方法:
   void start()    啟動執行緒
   final void setName(String name)    設定執行緒的名稱
   final String getName()     返回執行緒的名稱
   final void setPriority(int newPriority)    設定執行緒的優先順序
   final int getPriority()    返回執行緒的優先順序
   final void join() throws InterruptedException    等待該執行緒終止。(強行介入)
   final boolean isAlive()    判斷執行緒是否處於活動狀態
   void interrupt()    中斷執行緒

8、thread類中的常用靜態方法:
   static Thread currentThread()    返回對當前正在執行的執行緒物件的引用
   static void sleep(long millis) throws InterruptedException    使當前正在執行的執行緒休眠(暫停執行)
   static void yield()    讓出時間片
   static boolean interrupted()    判斷當前執行緒是否已經中斷


9、常用方法的解析
   優先順序:
   注意:1、多個執行緒處於可執行狀態時,將對cpu時間片進行競爭,優先順序高的,獲取的可能性則高
         2、 通過setPriority和getPriority方法來設定或返回優先順序;
         3、執行緒優先順序用1~10 表示,10的優先順序最高,預設值是5,1的優先順序最低


    sleep():使執行緒停止執行一段時間,此時將處於阻塞狀態。阻塞的時間由指定的毫秒數決定
    注意:1、執行緒睡眠是幫助所有執行緒獲得執行機會的最好方法
          2、執行緒睡眠到期自動甦醒,並返回到可執行狀態,不是執行狀態。

    yield():出讓時間片,但不會阻塞執行緒,轉入可執行狀態
    注意:1、如果呼叫了yield方法之後,如果沒有其他等待執行的執行緒, 這個時候當前執行緒就會馬上恢復執行!
   
    sleep()和yield()方法對比:   sleep()                                                    yield()
    1、暫停後的狀態            進入被阻塞的狀態,直到經過指定時間後,才進入可執行狀態      直接將當前執行緒轉入可執行狀態
    2、沒有其他等待執行的執行緒    當前執行緒會等待指定的時間後執行                              當前執行緒有可能會馬上恢復執行
    3、等待執行緒的優先級別                                    優先順序相同或更高的執行緒執行


    join():阻塞當前執行緒,強行介入執行


    final void setDaemon(boolean on)    將該執行緒設定為後臺執行緒
    final boolean isDaemon()            判斷該執行緒是否為後臺執行緒
    我們自己建立的執行緒,叫前臺執行緒也叫使用者執行緒。後臺執行緒建立的都叫後臺執行緒 。


10、執行緒同步
   
    需求:模擬三個視窗同時在售50張票

    問題1:為什麼50張票被賣出了150次?
    出現原因:因為num是非靜態的,非靜態的成員變數資料是在每個物件中都會維護一份資料的,三個執行緒物件就會有三份。
    解決方案:把num票數共享出來給三個物件使用。使用static修飾。

    問題2:剛剛的問題是解決了,但是為什麼會出現兩個視窗賣同一張票呢?--出現了執行緒安全問題
    解決方案:一個時間只能由一個執行緒操作內容---執行緒同步機制

   出現安全的根本原因:
   1、存在兩個或者兩個以上的執行緒物件,而且執行緒之間共享著一個資源
   2、有多個語句操作了共享資源


   同步機制的方法
   方式一:同步程式碼塊
   語法:synchronized(共享物件名){被同步的程式碼段}
   
   同步程式碼塊要注意的事項:
    1、任意一個物件都可以作為鎖物件。
    2、在同步程式碼塊中呼叫sleep方法並不會釋放鎖物件的。
    3、只有真正存線上程安全問題的時候才使用同步程式碼塊,否則會降低效率。
    4、多執行緒操作的鎖物件必須是唯一共享的,否則無效。eg:Static Object o = new Object()--是唯一   "鎖"--可以是唯一,儲存在常量池  new String("鎖")--不可以存在堆

   方式二:同步方法
   語法:訪問修飾符 synchronized 資料返回型別 方法名(){ … }

   同步方法要注意:
   1、如果是一個非靜態的同步方法的鎖,物件是this物件;如果是靜態的同步方法的鎖物件是當前函式所屬的類的位元組碼檔案(Class物件)。
   2、同步方法的鎖物件是固定的,不能由你來指定。
   
   
   推薦使用:同步程式碼塊
   原因:1、同步程式碼塊的鎖物件可以由我們隨意指定;同步方法的鎖物件是固定的,不能指定。
         2、同步程式碼塊可以很方便的需要被同步的範圍,同步方法必須是整個方法的所有程式碼都被同步了。

   執行緒同步的特點:   
      1、執行緒同步的優點:解決了執行緒安全問題、對公共資源的使用有序化
      2、執行緒同步的缺點:效能下降;會帶來死鎖


11、死鎖 :執行緒死鎖指的兩個執行緒互相持有對方依賴的共享資源,造成無限阻塞。
    案例電池和遙控器(張三拿電池,李四拿遙控器,誰也不肯放手)   張三等著李四的電池,李四等著張三的遙控器,無限等待中
    死鎖出現的根本原因: 1、存在兩個或者兩個以上的執行緒
                        2、存在兩個或者兩個以上的共享資源
    死鎖解決方案:沒有方案。只能儘量避免發生(或者執行緒通訊)

12、執行緒通訊:一個執行緒完成了自己的任務的時候,要通知另外一個執行緒去完成另外一個任務
    如何實現執行緒通訊:Java程式碼中基於對共享資料進行“wait()、notify()、notifyAll()"來實現多個執行緒的通訊。
    案例生產者和消費者
    問題一:出現了執行緒安全問題。 價格錯亂了...
    解決方案:加鎖
    問題二:生成一大片,消費一大片,要做成什麼樣呢?生產者生產完等待消費者消費,然後再去生產;消費者每消費完,那麼要等待生產者去生產,然後再消費。生產一個消費一個。      解決問題:通訊方法   
     
    執行緒通訊常用方法:
    wait():  等待--如果執行緒執行了wait方法,那麼該執行緒會進入等待的狀態,等待狀態下的執行緒必須要被其他執行緒呼叫notify方法才能喚醒。
    notify(): 喚醒--喚醒執行緒池等待執行緒其中的一個。
    notifyAll() : 喚醒執行緒池所有等待的執行緒。

   wait與notify方法要注意的事項:
    1. wait方法與notify方法是屬於Object物件 的。
    2. wait方法與notify方法必須要在同步程式碼塊或者是同步方法中才能使用。
    3. wait方法與notify方法必需要由鎖物件呼叫。


    執行緒通訊原理:
    wait():一個執行緒如果執行了wait方法,那麼該執行緒就會進去一個以鎖物件為標識的執行緒池中等待。
    notify():如果一個執行緒執行了notify方法,那麼就會喚醒以鎖物件為識別符號的執行緒中等待執行緒中的其中一個。

                     sleep()             wait()
    歸屬                     Thread的靜態方法    Object的方法
    作用                     讓本執行緒進入睡眠狀態    讓本執行緒進入“等待”狀態。
    是否釋放同步鎖     不會釋放同步鎖            會釋放同步鎖


13、執行緒的生命週期:參照ppt p62
    (1)新建狀態(New):使用new關鍵字建立執行緒物件,僅僅被分配了記憶體;
    (2)可執行狀態(Runnable):執行緒具備獲得CPU時間片的能力。執行緒進入可執行狀態的情況如下: 執行緒start()方法被呼叫; 當前執行緒sleep()、其它執行緒join()結束、等待使用者輸入完畢; 某個執行緒取得物件鎖; 當前執行緒時間片用完了,呼叫當前執行緒的yield()方法。
    (3)執行狀態(Running):執行run方法,此時執行緒獲得CPU的時間片;
    (4)阻塞狀態(Blocked):執行緒由於某些事件放棄CPU使用權,暫停執行。直到執行緒重新進入可執行狀態,才有機會轉到執行狀態。阻塞狀態分為如下幾種: 同步阻塞 – 執行緒獲得同步鎖,若被別的執行緒佔用,執行緒放入鎖池佇列中。 等待阻塞 – 執行緒執行wait()方法,執行緒放入等待佇列中。 其它阻塞 – 執行緒執行sleep()或join()或發出I/O請求。
    (5)死亡狀態(Dead):run、main() 方法執行結束,或者因異常退出了run()方法,執行緒進入死亡狀態,不可再次復生。
 

相關推薦

javase知識點 ----20 執行

1、程序:正在執行的程式稱作一個程序。程序負責了記憶體空間的劃分。    Windows號稱是多工的作業系統,那麼Windows是同時執行多個應用程式嗎?          從巨集觀角度:Windows確實是在同時執行多個應用程式。          從微觀角度:cpu是做了

iOS - 知識梳理執行

多執行緒:一個程序裡面開啟多條執行緒,每條執行緒可以單獨的執行不同的任務。 iOS實現多執行緒的方式: 1、pthread(C寫的、基本不用) 2、NSThread 3、gcd 4、NSOperation 下面分別介紹下後三個常用的多執行緒方式 NSThread: 使用方式

購物表動態連結串列+鬧鐘提醒執行

基本連結串列的應用 增 刪 查 找 排 模糊查詢 核心程式碼如下: #include <stdio.h> #include <math.h> #include <string.h> #include <malloc.h> #incl

實現客戶端寫入字串,在服務端翻轉後返回執行

實現客戶端寫入字串,在服務端翻轉後返回 服務端: package network.tcp; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import

Qt:Qt實現Winsock網路程式設計—TCP服務端和客戶端通訊執行

Qt實現Winsock網路程式設計—TCP服務端和客戶端通訊(多執行緒) 前言 感覺Winsock網路程式設計的api其實和Linux下網路程式設計的api非常像,其實和其他程式語言的網路程式設計都差不太多。博主用Qt實現的,當然不想用黑視窗唄,有介面可以看到,由於GUI程式設計

知識梳理執行

多執行緒:一個程序裡面開啟多條執行緒,每條執行緒可以單獨的執行不同的任務。 iOS實現多執行緒的方式: 1、pthread(C寫的、基本不用) 2、NSThread 3、gcd 4、NSOperation 下面分別介紹下後三個常用的多執行緒方式 NSThread:

Java之UDP傳輸聊天程式小Demo執行

ChatDemo.java import java.net.DatagramSocket; public class ChatDemo { public static void main(String[] args) { try {

QT實現哈夫曼壓縮執行

本人菜雞程式設計師一枚,最近剛剛學習的資料結構中的哈夫曼樹,就用QT寫了一個哈夫曼壓縮,話不多說先上步驟,再上程式碼。(如果有更好的想法,歡迎指點) 1.先寫出建最小堆和建哈夫曼樹程式碼(建最小堆的程式碼可以通過STL中的堆代替) 2.寫出壓縮類的程式碼,類中

周威學Go從入門到放棄第十篇執行

go語言多執行緒開發特別容易入門,通過go關鍵字實現,程式碼如下: package main import ( "fmt" "runtime" ) func say(s string) { for i := 0; i < 5; i++ { runtime

socket ( java ) 簡單個客戶端、服務端通訊執行

實現: 客戶端:多個socket(多個埠),其中一個客戶端的一個埠用於接收服務端傳送過來的訊息,其一個用於向服務端傳送訊息。其它客戶端只有發訊息的功能。 服務端:兩個socket,一個用於迴圈接收客戶端傳送過來的socket請求。一個用於接收訊息手自動向客戶端

Java大資料量執行分段分批處理

分段處理主類 package pers.zuo.component.piecewise; import java.util.ArrayList; import java.util.List; import java.util.concurrent.C

後臺小程式批量推送執行

一,建立需要的表 表名:t_push_task(推送任務表) 表格資訊 欄位 型別 註釋 鍵 能否為空 預設值 其他 id int(11) PRI NO 無 auto_increment

c#實現用SQL池執行,定時批量執行SQL語句

在實際專案開發中,業務邏輯層的處理速度往往很快,特別是在開發Socket通訊服務的時候,網路傳輸很快,但是一旦加上資料庫操作,效能一落千丈,資料庫操作的效率往往成為一個系統整體效能的瓶頸。面對這問題,我們怎麼辦呢?好,下面我就為大家介紹一種方法:構建SQL池,分離業務邏輯層

動態呼叫WebService的兩種方法執行

轉載:https://blog.csdn.net/huanglan513/article/details/46930393 在.net中,可以新增Web 引用來新增WebService,但是這種方法的缺陷是當WebService內的方法一變動,引用的系統這邊就必須更新引用,重新編譯,再發布,是不

作業系統上機作業--根據萊布尼茲級數計算PI1執行

pi1.c: 使用2個執行緒根據萊布尼茲級數計算PI • 萊布尼茲級數公式: 1 - 1/3 + 1/5 - 1/7 + 1/9 - ... = PI/4 • 主執行緒建立1個輔助執行緒

java中模擬一個阻塞佇列執行

模擬一個阻塞佇列,當這個佇列中滿了的話,再往裡新增元素則會阻塞在那裡,直到有元素取出的時候才能往裡加,取元素的時候,當佇列是空的時候則會阻塞在那裡,一直到有元素新增為止 import java.util.LinkedList; import java.util

runnable和thread的區別以及run和start的區別執行

在java中可有兩種方式實現多執行緒,一種是繼承Thread類,一種是實現Runnable介面;Thread類是在java.lang包中定義的。一個類只要繼承了Thread類同時覆寫了本類中的run()方法就可以實現多執行緒操作了,但是一個類只能繼承一個父類,這是此方法的

android 登入,傳送等待ProgressDialog執行

常常需要在登入,傳送或者其他時候需要等待網路,為了增加使用者體驗,這裡使用了ProgressDialog 下面直接放程式碼 ProgressDialog dialog;//新建一個ProgressDialog protected void onCreate(Bun

qt匯出、操作excel執行

使用QAxObject在多執行緒下進行excel操作,將原來固定格式的文字檔案,通過解析之後寫入到excel中。 效果圖 多執行緒使用 Worker *pWorker = new Worker(); connect(pWorker, SIGNAL(err

作業系統上機作業--根據萊布尼茲級數計算PI2執行

pi2.c: 使用N個執行緒根據萊布尼茲級數計算PI • 與上一題類似,但本題更加通用化,能適應N個核心,需要使用執行緒引數來實現 • 主執行緒建立N個輔助執行緒 • 每個輔助執行緒計