1. 程式人生 > >java學習筆記之初識多線程

java學習筆記之初識多線程

技術 運行 必須 dex ima this 認識 主線程 inf

初識多線程

一.進程的認識:

  1.進程的理解:

  進程可以理解成正在執行的任務,就是正在運行的程序,進程又分為兩種,一種是前臺進程,就是我們很直觀看見的,另一種是後臺進程,就是操作系統啟動就有的(系統級的進程),每個進程運行之後都會占用一定的cpu和內存資源;

  比如說:我們打開window任務管理器就可以看到有很多的進程,裏面有用戶開啟的,也有操作系統啟動的進程

技術分享圖片

  2.進程的調度:

  也就是那麽多的進程,cpu是怎樣運行的呢?

  采用時間片輪轉法

技術分享圖片

二.線程認識

  1.線程的理解

    線程是在進程的內部運行的執行體

    (1).一個進程可以創建多個線程

    (2).進程和線程共同來爭奪cpu,而且概率是均等的

    (3).線程依賴進程,不能獨立存在

    (4).在java中,一個進程至少有一個線程,main方法被稱為主線程;

      我們可以在java的main方法中輸出一個1/0;

技術分享圖片

    (5).進程或者線程都有優先級,優先級高的可以得到更多的時間片和cpu的執行權

    (6).搶占式調度:優先級高的進程可以搶占優先級低的cpu執行權

  2.為什麽要搞多線程?

   原因:

    (1).讓多個程序同時執行

    (2).提高程序的執行效率

三.線程的創建

  1.方式一:繼承Thread類

    小demo:

1 //定義一個類,繼承Thread類
2 public  class
MyThread extends Thread { 3 4 //重寫Thread類的run方法 5 public void run(){ 6 System.out.print("我是一個子線程"); 7 } 8 }

  

1 public class Demo {
2     public static void main(String[] args) {
3         //創建子類對象,然後調用start();方法
4         MyThread mt=new MyThread();
5         mt.start();
6 } 7 }

  2.方式二:實現Runnable接口

    小demo:

//實現類的定義
public class MyRunnableImpl  implements Runnable {
    //定義一個Runnable實現類,然後重寫run方法
    @Override
    public void run() {
        //這裏寫功能代碼
    }
}
 1 public class Demo {
 2     //使用代碼
 3     public static void main(String[] args) {
 4         //new 一個Runnable實現類對象
 5         MyRunnableImpl my=new MyRunnableImpl();
 6         //然後將該實現類對象,傳入Thread類的構造方法中,並創建Thread類對象
 7         //調用Thread對象start()方法開啟線程
 8         new Thread(my).start();
 9     }
10 }

四.線程的安全

  1.線程安全問題產生的原因:

      當多個線程去訪問共享資源時候,就會發生線程安全問題

    先看一個案例:多窗口賣電影票的案例

 1 class  Ticket implements Runnable {
 2     //電影票的數量
 3     private static  int ticket=100;
 4     @Override
 5     public void run() {
 6         while(true){
 7             if(ticket>0){
 8                 //模擬網絡延時的場景
 9                 try {
10                     Thread.sleep(50);
11                 } catch (InterruptedException e) {
12                     // TODO Auto-generated catch block
13                     e.printStackTrace();
14                 }
15                 //對票數進行出售(減減操作)
16                 System.out.println("正在售出第"+ticket--+"張票");
17             }
18         }
19     }
20 }
21 public class Demo {
22     public static void main(String[] args) {
23         //new 一個實現類對象
24         Ticket  t=new Ticket();
25         //創建3個線程對電影票進行售賣
26         new Thread(t).start();
27         new Thread(t).start();
28         new Thread(t).start();
29         
30     }
31 }

  這時候就出現了問題:

    技術分享圖片

    出現這個問題的解釋:

      當擁還剩一張電影票的時候,擁有cpu執行權的線程運行到while(true)的時候,順利通過,然後在運行sleep();這時候這個線程進入堵塞狀態,電影票還是1,cpu的執行權被另一個線程拿到,也正好運行到while(true),順利通過,然後在運行sleep();cpu執行權被第三個線程搶去,同樣的運行,到最後醒過來的線程會繼續執行下面的代碼。就產生了負數票的現象

   2.線程安全問題的解決方案:

     (1).同步代碼塊

    

 1      
 2      //定義一個對象,當做鎖對象
 3      static Object obj = new Object();
 4      /*
 5         同步代碼塊:
 6         參數:鎖對象
 7         1:java任何對象都可以作為鎖對象
 8         2:所有的線程都必須共享這個鎖對象(該對象只有一份)
 9         synchronized(mutex){
10             //存放需要加鎖的代碼
11         }
12       */
13     
14     //實現賣票的代碼
15     @Override
16     public void run() {
17         
18         while(true){
19             synchronized (obj) {//加鎖
20                 if(tickets > 0 ){
21                     //模擬一個網絡的延時
22                     try{Thread.sleep(50);}catch(Exception e){}
23                     System.out.println("正在出售第"+ tickets-- + "張票");
24                 }
25             }//解鎖
26         }
27     }

    (2).同步方法

 1     /*
 2      * 同步方法:對整個方法加鎖
 3      * 
 4      * 1:同步方法的鎖對象是this,  這裏的this必須是同一個
 5      * 2:靜態方法的鎖對象是:類名.class
 6      */
 7     /*
 8      * 同步代碼塊和同步方法的區別:
 9      *     1:同步代碼塊可以對任何一段代碼進行加鎖
10      *  2:同步方法是對整個方法都進行加鎖
11      *  
12      *  
13      *  3:同步代碼塊的對象可以自己指定
14      *  4:同步方法的鎖對象必須是this
15      */
16     public synchronized void method(){
17         if (tickets > 0) {
18             // 模擬一個網絡的延時
19             try {
20                 Thread.sleep(50);
21             } catch (Exception e) {
22             }
23             System.out.println("正在出售第" + tickets-- + "張票");
24         }
25     }
26 
27     // 實現賣票的代碼
28     @Override
29     public void run() {
30 
31         while (true) {
32             method();
33         }
34     }

    (3).同步鎖

 1 /*
 2      * 同步鎖:
 3      *  Lock接口:
 4      *      ReentrantLock實現類:
 5      *         lock();    加鎖
 6      *         unlock();解鎖
 7      */
 8     
 9     //1:創建鎖對象
10     ReentrantLock rt = new ReentrantLock();
11     
12     
13     // 實現賣票的代碼
14     @Override
15     public void run() {
16 
17         while (true) {
18             //2:在適當的地方加鎖
19             rt.lock();
20             
21             if (tickets > 0) {
22                 // 模擬一個網絡的延時
23                 try {
24                     Thread.sleep(50);
25                 } catch (Exception e) {
26                 }
27                 System.out.println("正在出售第" + tickets-- + "張票");
28             }
29             //3:在適當的地方解鎖
30             rt.unlock();
31         }
32     }

五.線程的狀態

技術分享圖片

  

java學習筆記之初識多線程