Thread

Thread概念

程序(Process)是把程式碼載入到記憶體,從執行到執行完畢的一個過程。

操作系統(OS)可以管理多個程序(Process),可以讓多個程序(Process)輪流使用CPU資源。

Jvm視為虛擬的操作系統,管理一個程序中的多個執行緒(多個流程)。

執行緒(Thread)是流程,每個程序都會有一個主要執行緒(Main Thread)也稱作主要流程,為了執行效率提升,所以想同時運行很多流程,每一個執行緒就是一個流程,所以建立了很多執行緒(Thread)。

所以一個程序可以運行很多流程(執行緒Thread),實際上是Jvm有一個排程管理系統,會十分快速的將一個流程(執行緒)切換到另一個流程(執行緒),快速的切換讓使用者以為是同時運行這些流程(執行緒),實際上是十分快速的輪流執行(執行緒)。

建立Thread

建立Thread有二個方式,一個是new建立,一個是繼承thread類別。

new建立

建立的時候,建構子的參數是要Runnable物件。

語法

1
new Thread(new Runnalbe() {});

也可以先寫好Runnable的物件再代入參數中

1
2
public class 類別名 implements Runnable {}
new Thread(new 類別名());

繼承thread類別

1
public class 類別名 extends Thread {}

覆寫run()方法

run()方法裡面放的是程式執行的流程,也就是這個執行緒要執行的流程。

Runnable覆寫run()方法

語法

1
2
3
4
5
6
new Thread(new Runnable() {
  @Override
  public void run() {
    // 要執行的流程
  }
})

也可以先寫好Runnable的物件再代入參數中

1
2
3
4
5
6
7
public class 類別名 implements Runnable {
  @Override
  public void run() {
    // 要執行的流程
  }  
}
new Thread(new 類別名());

繼承thread類別

語法

1
2
3
4
5
6
public class 類別名 extends Thread {
  @Override
  public void run() {
    // 要執行的流程
  }
}

匿名類別的方式建立thread類別

1
2
3
4
5
6
new Thread() {
  @Override
  public void run() {
    // 要執行的流程
  }
};

運行

呼叫Thread類別的start()方法,start()方法就會去執行覆寫run()方法中的程式碼。

new Thread呼叫start()

語法

1
2
3
4
new Thread(new Runnable() {
  @Override
  public void run() { ... }
}).start()

也可以先寫好Runnable的物件再代入參數中

1
2
3
4
5
6
7
public class 類別名 implements Runnable {
  @Override
  public void run() {
    // 要執行的流程
  }  
}
new Thread(new 類別名()).start();

extends Thread呼叫start()

語法

1
2
3
4
5
public class 類別名 extends Thread {
  @Override
  public void run() { ... }
}
new 類別名().start();

匿名類別的方式建立thread類別

1
2
3
4
5
6
new Thread() {
  @Override
  public void run() {
    // 要執行的流程
  }
}.start();

執行緒共享資源

所謂的共享是不同的執行緒(Thread)使用相同的變數(相同的記憶體位址),不同的執行緒對相同的變數進行存取動作。

Runnable共享資源

只要建立一個Runnable物件,多個執行緒可以共享同一個Runnable物件的變數,類別可以實作很多介面interface。

Runnable物件:AntR.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class AntR implements Runnable{
  int cake;
  public void setCake(int c) {
    cake = c;
  }
  @Override
  public void run() {
    int n = 2;
    while (true) {
      if (cake <= 0) {
        System.out.println(Thread.currentThread().getName() + " 死亡");
        //!!!十分重要,結束循環
        return;
      }
      // 多個執行緒使用同一個cake變數
      cake = cake - n;
      System.out.println(Thread.currentThread().getName() + "吃" + n + "g,蛋糕剩下" + cake + "g");
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public static void main(String[] args) {
  // 只要建立一個Runnable物件
  AntR runnableObj = new AntR();
  runnableObj.setCake(10);
  // 參數用同一個Runnable物件
  Thread antRed = new Thread(runnableObj);
  antRed.setName("紅螞蟻");
  // 參數用同一個Runnable物件
  Thread antBlack = new Thread(runnableObj);
  antBlack.setName("黑螞蟻");
  antRed.start();
  antBlack.start();
}
紅螞蟻吃2g,蛋糕剩下8g
黑螞蟻吃2g,蛋糕剩下6g
黑螞蟻吃2g,蛋糕剩下2g
紅螞蟻吃2g,蛋糕剩下4g
黑螞蟻吃2g,蛋糕剩下0g
紅螞蟻 死亡
黑螞蟻 死亡

繼承Thread共享資源

繼承Thread的優點是可以共享成員變數與成員方法,缺點是Java不支援多繼承,繼承Thread後就沒辦法繼承其它類別。

Cake.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Cake {
  int size;
  public void setSize(int size) {
    this.size = size;
  }
  public int getSize() {
    return size;
  }
  public void lost(int n) {
    if (size - n >= 0) {
      size = size - n;
    }
  }
}

Ant.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Ant extends Thread{
  Cake cake;
  public Ant(String name, Cake cake) {
    this.cake = cake;
    setName(name);
  }
  @Override
  public void run() {
    while (true) {
      int n = 2;
      cake.lost(n);
      System.out.println(getName()+" 吃 " + n + "g蛋糕, 蛋糕剩下"+ cake.getSize() +"g");
      try {
        sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      if (cake.getSize() <= 0) {
        System.out.println(getName() + "已死亡");
        //!!!十分重要,結束循環
        return;
      }
    }
  }
}
1
2
3
4
5
6
7
8
public static void main(String[] args) {
  Cake cake = new Cake();
  cake.setSize(10);
  Ant antRed = new Ant("red ant", cake);
  Ant antBlack = new Ant("Black ant", cake);
  antRed.start();
  antBlack.start();
}
Black ant 吃 2g蛋糕, 蛋糕剩下6g
red ant 吃 2g蛋糕, 蛋糕剩下8g
Black ant 吃 2g蛋糕, 蛋糕剩下4g
red ant 吃 2g蛋糕, 蛋糕剩下2g
Black ant 吃 2g蛋糕, 蛋糕剩下0g
red ant已死亡
Black ant已死亡

同步與非同步

同步synchronous

等待上一個動作完成,才可以處理下一個動作。

非同步asynchronous

不用等待上一個動作完成,可以同時做多個動作。
多個流程或稱執行緒(thread)同時進行,不用特別等上一個流程(執行緒)完成,才能進行下一個流程(執行緒)。

同步鎖lock

非同步(asynchronous)的流程中,共享資源時造成變數值不一致,因為多個流程(執行緒thread)同時存取或修改同一個變數,所以需要使用同步鎖(lock),必須把目前的流程(thread)處理完,才輪下一個流程(thread)處理,還原成同步的狀況,所有流程(thread)排隊,等待進入廁所(要同步的區域),只有拿到鎖(lock)的流程(thread),才能進入廁所,鎖上(lock)廁所門,上完廁所(執行完),把廁所門的鎖打開(unlock),輪到下一個排隊的執行緒(thread)去上廁所。

img

results matching ""

    No results matching ""