黑馬:多線程一

來源:互聯網
上載者:User

1、進程

是一個執行中的程式,每一個進程執行都有一個執行順序,該執行順序是一個執行路徑,或者叫一個控制單元。
線程:就是進程中的一個獨立的控制單元,線程式控制制著進程的執行。一個進程中至少有一個線程。
Java jvm啟動的時候會有一個進程java.exe,該進程中至少一個線程負責java程式的執行,而且這個線程啟動並執行代碼存在於main方法中,該線程稱之為主線程。
java jvm啟動還會啟動一個線程,負責記憶體回收機制的線程。

如何在自訂的代碼中,自訂一個線程?線程2種方式:
建立線程的第一種方式:繼承Thread類。
步驟:
第一、定義類繼承Thread。
第二、覆寫Thread類中的run方法。目的是將自訂的代碼寫入run方法中。
第三、調用線程的start方法,該方法有兩個作用,啟動線程、調用run方法。
run方法和start方法不同點:
run方法僅僅是對象調用run方法,建立了線程,但是線程並沒有運行。
start方法是開啟了線程,並執行該線程的run方法。

class Demo extends Thread{ public void run(){  for(int x=0;x<50;x++){   System.out.println("demo run--->"+x);  } }}public class ThreadDemo01 { public static void main(String[] arg){  Demo d= new Demo();  d.start();    for(int x=0;x<50;x++){   System.out.println("ThreadDemo run===>"+x);  } }}

建立線程的第二種方式:實現Runnable介面
步驟:
第一、定義類來實現Runnable介面;
第二、覆蓋Runnable介面中的run方法,將線程要啟動並執行代碼存放在該run方法中。
第三、通過Thread類建立線程對象。
第四、將Runnable介面的子類對象作為實際參數傳遞給Thread的建構函式。因為自訂的run方法所屬的對象是Runnable介面的子類對象,所以要讓線程去指定對象的run方法,就必須明確該run方法所屬對象。
第五、調用Thread類的start方法開啟線程病調用Runnable介面子類的run方法。

class Demo03 implements Runnable{ private int tick = 100; public void run(){  while(true){   if(tick>0){    System.out.println(Thread.currentThread().getName()+"..sale.."+tick--);   }  } }}public class ThreadDemo03 { public static void main(String[] args){  Demo03 d = new Demo03();  Thread t = new Thread(d);  t.start(); }}

實現方式和繼承方式區別:
一般用實現方式,因為實現方式可以避免繼承的單繼承缺點。
2、線程的運行狀態
建立:new一個thread對象或者其子類對象就是建立一個線程。
就緒:建立的對象調用了start方法。
運行:對象的運行方法定義在run中。
凍結:sleep、wait(notify)。
死亡:stop。
3、擷取線程對象及名稱
線程都有自己預設的名稱,Thread-編號,該編號從0開始。Static Thread currentThread()擷取當前線程對象。getName()擷取線程名稱。設定線程名稱:setName或者建構函式。
4、多線程的安全問題
多線程出現安全問題的原因:當多條語句在操作同一個線程共用資料的時候,一個線程對多條語句只執行了一部分,還沒有執行完,另一個線程就參與進來執行,導致共用資料的錯誤。
解決多安全執行緒問題方法:多多條操作共用資料的語句,只能讓一個線程都執行完。在執行過程中,其他線程不可以參與進來。
java對於多線程的安全問題提供了專業的解決辦法:
方法一、同步代碼塊。
synchronized(對象){
 需要被同步的代碼塊
}
對象如同鎖,持有鎖的線程可以在同步代碼塊中執行,沒有持有鎖的線程即使擷取cpu的執行權,也進不去,因為沒有擷取鎖。
同步的前提:
第一、必須要有兩個或者以上的線程; 第二、必須是多個線程使用同一個鎖。
第三、必須保證同步中只能有一個線程在運行。
同步的好處:解決了多線程的安全問題。
同步的弊端:多個線程需要判斷鎖,比較消耗資源。
方法二、同步函數
函數傳回值類型  synchronized 函數名(..){…}
如何找需要同步的代碼
第一、明確哪些代碼是多線程運行代碼;
第二、明確共用資料;
明確多線程運行代碼中哪些語句是操作共用資料的。
5、同步函數的鎖是this
同步函數用的是哪一個鎖?函數需要被對象調用,那麼函數都有一個所屬對象引用,就是this,所以同步函數使用的鎖是this。

class Ticket implements Runnable{ private int ticket = 100; Object obj = new Object(); boolean flag = true; public void run(){  if(flag){   while(true){    synchronized(this){//同步代碼塊用的鎖自己可以定義一個對象     if(ticket>0){      try{Thread.sleep(10);}catch(Exception e){}      System.out.println(Thread.currentThread().getName()+"..sale.."+ticket--);      }     }   }  }else{   while(true){    show();    }   } } public synchronized void show(){//同步函數用的鎖為this   if(ticket>0){    try{Thread.sleep(10);}catch(Exception e){}    System.out.println(Thread.currentThread().getName()+"****show****"+ticket--);   } }}public class ThreadDemo{ public static void main(String[] args){  Ticket t = new Ticket();    Thread t1 = new Thread(t);  Thread t2 = new Thread(t);  t1.start();  try{Thread.sleep(10);}catch(Exception e){}  t.flag = false;  t2.start();    } }

6、靜態同步函數的鎖是Class對象
如果同步函數被靜態修飾後,使用的鎖不再是this,而是Class對象。因為靜態方法中不可以定義this,當靜態函數進記憶體時,記憶體中沒有本類對象,但有本類對應的位元組碼檔案對象,就是類名.clss,該對象的類型是Class。

class Ticket implements Runnable{ private static int ticket = 100; boolean flag = true; public void run(){  if(flag){   while(true){    synchronized(Ticket.class){//靜態同步方法鎖是本類位元組碼對象     if(ticket>0){      try{Thread.sleep(10);}catch(Exception e){}      System.out.println(Thread.currentThread().getName()+"..sale.."+ticket--);      }     }   }  }else{   while(true){    show();    }   } } public static synchronized void show(){//靜態同步函數用的鎖為Ticket.class位元組碼對象,即Class對象。   if(ticket>0){    try{Thread.sleep(10);}catch(Exception e){}    System.out.println(Thread.currentThread().getName()+"****show****"+ticket--);   } }}public class ThreadDemo{ public static void main(String[] args){  Ticket t = new Ticket();    Thread t1 = new Thread(t);  Thread t2 = new Thread(t);  t1.start();  try{Thread.sleep(10);}catch(Exception e){}  t.flag = false;  t2.start();    } }

7、單例設計模式
單例設計思想:
為了其他程式過多建立該類對象,禁止其他程式建立該類對象---將建構函式私人化。
為了讓其他程式能訪問到該類對象,在本類中定義一個對象。---》在類中建立一個本類對象。
為了方便其他程式對自訂兌現的訪問,可以對外提供一些訪問方式---》提供一個方法可以擷取該對象。
第一、餓漢式

class SingleDemo{ private SingleDemo(){} private static final SingleDemo s = new SingleDemo(); public static SingleDemo getInstance(){  return s; }}

第二、懶漢式

class Single02{ private Single02(){} private static Single02 instance = null; public static Single02 getInstance(){  if(instance==null){//雙重否定加同步   synchronized(Single02.class){//鎖為該類所屬的位元組碼檔案    if(instance==null){     instance = new Single02();     }   }  }  return instance;  }}

8、死結
a鎖調用b鎖,b鎖調用a鎖,迴圈至死。

總結:

1、實現線程的兩種方式:繼承Thread類,實現Runnable介面。
2、單例設計模式中餓漢式使用了同步避免bug。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.