Java併發(一)線程管理

    在計算機領域中,我們說的併發(Concurrency)是指一系列任務的同時運行。如果一臺電腦有多個處理器或者有一個多核處理器,這個同時性(Simultaneity)是真正意義的併發;但是如果一臺電腦只有一個單核處理器,這個同時性並不是真正的併發

    一、線程的創建和運行

  • 繼承Thread類,並覆蓋run()方法

  • 創建一個Runnable接口的類。使用帶參數的Thread構造器來創建Thread對象。這個參數就是實現Runnable接口的類的一個對象

範例實現:

package org.test.concurrency;
/**
 * @author kucs
 * 
 * 創建一個實現Runnable接口的類。使用帶參數的Thread構造器來創建對象
 * 這個參數就是實現Runnable接口的類的一個對象
 * 
 */
public class Calculator implements Runnable {
 private int number;
 
 public Calculator(int number) {
  this.number = number;
 }
 @Override
 public void run() {
  // TODO Auto-generated method stub
  for(int i = 0;i < 10;i++){
   System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(),number,i,i*number);
  }
 }
}
package org.test.concurrency;
public class Main {
 public static void main(String[] args) {
  /* 創建一個執行10次的循環
   * 每次循環創建一個Calculator對象和一個Thread對象
   * 這個Thread對象使用剛創建的Calculator對象作爲構造器的參數
   * 然後調用剛創建的Thread對象的start()方法
   */
  for(int i = 0;i < 10;i++){
   Calculator calculator = new Calculator(i);
   Thread thread = new Thread(calculator);
   thread.start();
  }
 }
}

運行結果

wKiom1dOki7BkgYbAABAcqylEz4036.png-wh_50

當調用Thread對象的start()方法時,另一個執行線程將被創建。

如果某一個線程調用了System.exit()指令來結束程序的執行,所有的線程都將結束

對於一個實現了Runable接口的類來說,創建Thread對象並不會創建一個新的執行線程;同樣的,調用它的run()方法,也不會創建一個新的線程。只有調用它的start()方法,纔會創建一個新的執行線程。

    二、線程信息的獲取和設置

    Thread類有一些保存信息的屬性。這些屬性可以用來標識線程的狀態或者控制線程的優先級。

    ID:保存了線程唯一的標識符

    Name:保存了線程名

    Priority:保存了線程對象的優先級。線程的優先級從1到10逐次遞增。不建議改變線程優先級

    Status:保存了線程的狀態。在java中,線程有6中狀態:new,runnable,blocked,waiting,time waiting或者terminated

    

    jdk6版本的的Thread部分源碼

public class Thread implements Runnable {
  /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
    private char name[];
    private int         priority;
    private Thread threadQ;
    private long eetop;
    /* Whether or not to single_step this thread. */
    private boolean single_step;
    /* Whether or not the thread is a daemon thread. */
    private boolean daemon = false;
    /* JVM state */
    private boolean stillborn = false;
    /* What will be run. */
    private Runnable target;
    /* The group of this thread */
    private ThreadGroup group;
    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;
    /* The inherited AccessControlContext of this thread */
    private AccessControlContext inheritedAccessControlContext;
    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
 return threadInitNumber++;
    }
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
    private long stackSize;
    /*
     * JVM-private state that persists after native thread termination.
     */
    private long nativeParkEventPointer;
    /*
     * Thread ID
     */
    private long tid;

我們對Main類進行改造,代碼如下

package org.test.concurrency;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.State;
public class Main {
 public static void main(String[] args) {
  /*
   * 創建一個容量爲10的線程數組,用來存儲線程 創建一個容量爲10的Thread.State數組,用來存儲線程狀態
   */
  Thread[] threads = new Thread[10];
  Thread.State[] states = new Thread.State[10];
  /*
   * 創建一個容量爲10的Calculator對象數組,爲每個對象都設置不同的數字
   * 然後使用它們作爲Thread構造器的參數來創建10個線程對象。 將5個線程優先級設置爲最高,5個設置爲最低
   */
  for (int i = 0; i < 10; i++) {
   threads[i] = new Thread(new Calculator(i));
   if ((i % 2) == 0) {
    threads[i].setPriority(Thread.MAX_PRIORITY);
   } else {
    threads[i].setPriority(Thread.MIN_PRIORITY);
   }
   threads[i].setName("Thread " + i);
  }
  /*
   * 創建一個PrintWriter對象,用來把線程的狀態寫入文件
   */
  try {
   File file = new File("D:\\thread_log.txt");
   if(!file.exists()){
    file.createNewFile();
   }
   FileWriter fw = new FileWriter(file);
   PrintWriter pw = new PrintWriter(fw);
   for (int i = 0; i < 10; i++) {
//    System.out.println("Main : Status of Thread " + i + ":" + threads[i].getState());
    pw.println("Main : Status of Thread " + i + ":" + threads[i].getState());
    states[i] = threads[i].getState();
   }
   /* 開始執行10個線程 */
   for (int i = 0; i < 10; i++) {
    threads[i].start();
   }
   boolean finish = false;
   while(!finish){
    for(int i = 0;i<10;i++){
     if(threads[i].getState() != states[i]){
      writeThreadInfo(pw,threads[i],states[i]);
     }
    }
   }
   finish = true;
   for(int i = 0;i<10;i++){
    finish = finish && (threads[i].getState() == State.TERMINATED);
   }
   pw.close();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
 }
 private static void writeThreadInfo(PrintWriter pw, Thread thread, State state) {
  // TODO Auto-generated method stub
  pw.printf("Main : Id %d - %s\n", thread.getId(),thread.getName());
  pw.printf("Main : Priority: %d\n", thread.getPriority());
  pw.printf("Main : old State: %s\n", state);
  pw.printf("Main :", "***************************\n");
 }
}

運行結果

Main : Status of Thread 0:NEW
Main : Status of Thread 1:NEW
Main : Status of Thread 2:NEW
Main : Status of Thread 3:NEW
Main : Status of Thread 4:NEW
Main : Status of Thread 5:NEW
Main : Status of Thread 6:NEW
Main : Status of Thread 7:NEW
Main : Status of Thread 8:NEW
Main : Status of Thread 9:NEW
Main : Id 9 - Thread 0
Main : Priority: 10
Main : old State: NEW
Main :Main : Id 10 - Thread 1
Main : Priority: 1
Main : old State: NEW
Main :Main : Id 11 - Thread 2
Main : Priority: 10
Main : old State: NEW
Main :Main : Id 12 - Thread 3
Main : Priority: 1
Main : old State: NEW
Main :Main : Id 13 - Thread 4
Main : Priority: 10
Main : old State: NEW
Main :Main : Id 14 - Thread 5
Main : Priority: 1
Main : old State: NEW
Main :Main : Id 15 - Thread 6

    三、線程的中斷

    Java提供了線程中斷機制,我們可以使用它來結束一個線程。這種機制要求檢查它是否被中斷了,然後決定是不是響應這個中斷請求。線程忽略中斷請求並繼續執行。我們用isInterrupted()方法來檢查線程是否被中斷。如果isInterrupted()返回值是true,則表示線程中斷了。我們用thread.interrupt()來中斷線程。

    四、線程的休眠和恢復

    通過線程的sleep()方法來打到讓線程休眠的狀態。線程休眠狀態下不佔用計算機任何資源。sleep()方法接受整形數值作爲參數,表明線程掛起執行的毫秒數

    sleep()方法的另一種使用方式是通過TimeUnit枚舉類元素調用。這個方法也使用Thread類的sleep()方法來使當前線程休眠。

    五、等待線程的終止

    在一些情形下我們必須等待線程的終止。爲了達到這個目的,我們使用Thread的join()方法。當一個線程對象的join()方法被調用時,調用它的線程將被掛起,直到這個線程對象完成它的任務。

    六、守護線程

    Java裏有一種特殊的線程叫守護線程(Daemon)。這種線程的優先級很低,通常來說,當同一個應用程序中沒有其他線程運行的時候,守護線程才運行。當守護線程是程序中唯一運行的程序時,守護線程執行結束後,JVM也就結束了這個程序。

    通常守護線程是無限循環的,以等待服務請求或者執行線程的任務。他們不能做重要的工作,因爲我們不可能知道守護線程什麼時候能夠獲取CPU時間片,並且在沒有其他線程運行的時候,守護線程隨時可能結束。一個典型的守護線程是Java的垃圾回收器(Garbage Collector)。

    七、線程的分組

    Java提供ThreadGroup類表示一組線程。線程組可以包含線程對象,可以包括其他的線程組對象,它是一個樹形結構。相似內容請看Java多線程基礎


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章