多線程概述
-
搶占式多任務
直接中斷而不需要事先和被中斷程序協商
-
協作多任務
被中斷程序同意交出控制權之后才能執行中斷
-
多線程和多進程區別?
本質的區別在于每個進程有它自己的變量的完備集,線程則共享相同的數據
Thread
-
Thread(Runnable target)
構造有一個新的線程來調用指定的target的run()方法
-
void start()
啟動這個線程,將引發調用run()方法
-
void run()
調用關聯Runnable的run方法
Thread 示例測試代碼
public class ThreadTest extends Thread {
private Thread mThread;
private String mName;
private final int mCount = 4;
public ThreadTest(String name){
this.mName = name;
System.out.println("new ThreadTest"+name);
}
public void run(){
System.out.println("run " + this.mName);
try {
for (int i = 0; i < mCount; i++) {
System.out.println(this.mName + "Thread.sleep : " + i);
Thread.sleep(50);
}
} catch (InterruptedException ie) {
System.out.println("InterruptedException " + this.mName);
}
}
public void start() {
System.out.println("start " + this.mName);
if (this.mThread == null) {
this.mThread = new Thread(this);
this.mThread.start();
}
}
public static void main(String[] args) {
ThreadTest thread1 = new ThreadTest("test1");
thread1.start();
ThreadTest thread2 = new ThreadTest("test2");
thread2.start();
}
}
Runnable
Runnable封裝一個異步運行的任務
Runnable示例測試代碼
/**
* Runnable繼承類
*/
public class RunnableTest implements Runnable {
private Thread mThread;
private String mName;
private final int mCount = 4;
public RunnableTest(String name) {
this.mName = name;
System.out.println("new RunnableTest" + name);
}
public void run() {
System.out.println("run " + this.mName);
try {
for (int i = 0; i < mCount; i++) {
System.out.println(this.mName + "Thread.sleep : " + i);
Thread.sleep(50);
}
} catch (InterruptedException ie) {
System.out.println("InterruptedException " + this.mName);
}
}
public void start() {
System.out.println("start " + this.mName);
if (this.mThread == null) {
this.mThread = new Thread(this);
this.mThread.start();
}
}
public static void main(String[] args) {
RunnableTest run1 = new RunnableTest("test1");
run1.start();
RunnableTest run2 = new RunnableTest("test2");
run2.start();
}
}
Callable和Future
Callable接口是一個參數化的類型,有一個方法call
Future保存異步計算的結果。當使用Future對象,啟動有一個計算,把計算結果給某線程,Future對象在所有者結果計算好之后就可以得到它
-
call()
運行一個將產生結果的任務
代碼示例
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableTest implements Callable<Integer> {
public Integer call() throws Exception {
int i = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
return i;
}
public static void main(String[] args) {
CallableTest test = new CallableTest();
FutureTask<Integer> task = new FutureTask<Integer>(test);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " 的循環變量i的值" + i);
if (i == 20) {
new Thread(task, "有返回值的線程").start();
}
}
try {
System.out.println("子線程的返回值:" + task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
線程池
如果你的程序創建了大量生存期很短的線程,就應該使用線程池一個線程池包含大量準備運行的空閑線程。將一個Runnable對象給線程池,線程池中的一個線程就會調用run方法。
- newCachedThreadPool 構建,如果有空閑線程可用,立即讓它執行任務,否則創建一個新線程
- newFixedThreadPool 創建一個大小固定的線程池。如果提交的任務數大于空閑線程數,那么得不到服務的任務將被置于隊列中
- newSingleTreadExecutor是一個退化了大小為1的線程池