在計算機領域中,我們說的併發(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(); } } }
運行結果
當調用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多線程基礎