什麼是多線程
Java 給多線程編程提供了內置的支持。 一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。
多線程是多任務的一種特別的形式,但多線程使用了更小的資源開銷。
這裏定義和線程相關的另一個術語 - 進程:一個進程包括由操作系統分配的內存空間,包含一個或多個線程。一個線程不能獨立的存在,它必須是進程的一部分。一個進程一直運行,直到所有的非守護線程都結束運行後才能結束。
多線程能滿足程序員編寫高效率的程序來達到充分利用 CPU 的目的。
如何使用
繼承Thread類創建線程
/**
* 多線程實現的第一種方法,繼承Thread
*
*/
//1.自定義一個類,繼承java.lang包下的Thread類
class MyThread extends Thread {
//2.重寫run方法
public void run() {
//3.將要在線程中執行的代碼編寫在run方法中
for(int i = 0; i < 1000; i++) {
System.out.println("monkey");
}
}
}
public class ThreadTest01 extends Thread {
public static void main(String[] args) {
//4.創建上面自定義類的對象
//創建一個線程
MyThread mt = new MyThread();
//5.調用start方法啓動線程
mt.start();
//將循環的次數設置多一些,否則還沒等到CPU切換就已經打印完成了
for(int i = 0; i < 1000; i++) {
System.out.println("1024");
}
}
}
實現Runnable接口創建線程
/**
* 多線程實現的第二種方法,實現Runnable接口
*
*/
// 1.自定義一個類實現java.lang包下的Runnable接口
class MyRunnable implements Runnable {
// 2.重寫run方法
@Override
public void run() {
// 3.將要在線程中執行的代碼編寫在run方法中
for (int i = 0; i < 1000; i++) {
System.out.println("monkey");
}
}
}
public class ThreadTest02 {
public static void main(String[] args) {
// 4.創建上面自定義類的對象
MyRunnable mr = new MyRunnable();
// 5.創建Thread對象並將上面自定義類的對象作爲參數傳遞給Thread的構造方法
Thread t = new Thread(mr);
//6.調用start方法啓動線程
t.start();
for (int i = 0; i < 1000; i++) {
System.out.println("1024");
}
}
}
實現Callable接口創建線程
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* 多線程實現的第三種方法,實現Callable接口 優點: 可以獲取返回值 可以拋出異常
*/
//1.定義一個類實現Callable<V>接口
class MyCallable implements Callable<Integer> {
//睡眠時間
private long second;
//計算階乘
private int count;
public MyCallable(int count, long second) {
this.count = count;
this.second = second;
}
// 2.重寫call方法
@Override
public Integer call() throws Exception {
// 3.將要執行的代碼寫在call方法中
// 計算階乘
//讓當前線程睡眠,單位是毫秒
Thread.sleep(second);
int sum = 1;
if (count == 0) {
sum = 0;
} else {
for (int i = 1; i <= count; i++) {
sum *= i;
}
}
// 打印線程名稱
System.out.println(Thread.currentThread().getName() + "-----sum=" + sum);
return sum;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public class ThreadTest03 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//4.創建ExecutorService線程池
ExecutorService exec = Executors.newCachedThreadPool();
//5.創建存儲Future對象的集合,用來存放ExecutorService的執行結果
ArrayList<Future<Integer>> results = new ArrayList<Future<Integer>>();
//6.開啓2個線程,將返回的Future對象放入集合中
for (int i = 0; i < 2; i++) {
if (i == 0) {
//計算5的階乘,睡眠10秒
results.add(exec.submit(new MyCallable(5, 10000)));
} else {
//計算3的階乘,睡眠i秒
results.add(exec.submit(new MyCallable(3, i)));
}
}
for (Future<Integer> fs : results) {
//7.判斷線程是否執行結束,如果執行結束就將結果打印
if (fs.isDone()) {
System.out.println("計算結果:" + fs.get());
} else {
System.out.println(fs.toString() + "該線程還沒有計算完畢,請耐心等待");
}
}
//8.關閉線程池,不再接收新的線程,未執行完的線程不會被關閉
exec.shutdown();
System.out.println("main方法執行結束");
}
}
三種實現方式的比較
- 繼承Thread
- 優點:可以直接使用Thread類中的方法,代碼簡單
- 缺點:繼承Thread類之後就不能繼承其他的類
- 實現Runnable接口
- 優點:即時自定義類已經有父類了也不受影響,因爲可以實現多個接口
- 缺點: 在run方法內部需要獲取到當前線程的Thread對象後才能使用Thread中的方法
- 實現Callable接口
- 優點:可以獲取返回值,可以拋出異常
- 缺點:代碼編寫較爲複雜