一.進程與線程
進程:是代碼在數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位
線程:是進程中的一個執行路徑,是cpu分配的基本單位。一個進程最少擁有一個線程。
二. Java多線程的創建及啓動
1.繼承Thread類
優點獲取當前線程簡單直接使用this即可,缺點java不支持多繼承,繼承了Thread就無法繼承其他類了。
public class MyThread extends Thread {
private int i = 0;
@Override
public void run() {
for (i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
// 創建一個新的線程 myThread1 此線程進入新建狀態
Thread myThread1 = new MyThread();
// 創建一個新的線程 myThread2 此線程進入新建狀態
Thread myThread2 = new MyThread();
// 調用start()方法使得線程進入就緒狀態
myThread1.start();
// 調用start()方法使得線程進入就緒狀態
myThread2.start();
}
}
}
}
2.實現Runnable接口
優點接口可以多實現,減少耦合
public class MyRunnable implements Runnable {
private int i = 0;
@Override
public void run() {
for (i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
// 創建一個Runnable實現類的對象
Runnable myRunnable = new MyRunnable();
// 將myRunnable作爲Thread target創建新的線程
Thread thread1 = new Thread(myRunnable);
Thread thread2 = new Thread(myRunnable);
// 調用start()方法使得線程進入就緒狀態
thread1.start();
thread2.start();
}
}
}
}
說明: 繼承Thread類與實現Runnable接口創建線程方式相似,不同的地方在於,因爲Thread類本身也是實現了Runnable接口。
/**Thread類中對Runnable接口中run()方法的實現*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
也就是說,當執行到Thread類中的run()方法時,會首先判斷target是否存在,存在則執行target中的run()方法,也就是實現了Runnable接口並重寫了run()方法的類中的run()方法
3.使用Callable接口和FutureTask類創建線程
優點是具有返回值
public class MyCallable implements Callable<Integer> {
private int i = 0;
// 與run()方法不同的是,call()方法具有返回值
@Override
public Integer call() {
int sum = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
sum += i;
}
return sum;
}
}
public class ThreadTest {
public static void main(String[] args) {
// 創建MyCallable對象
Callable<Integer> myCallable = new MyCallable();
// 使用FutureTask來包裝MyCallable對象
FutureTask<Integer> ft = new FutureTask<Integer>(myCallable);
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 30) {
// FutureTask對象作爲Thread對象的target創建新的線程
Thread thread = new Thread(ft);
// 線程進入到就緒狀態
thread.start();
}
}
System.out.println("主線程for循環執行完畢..");
try {
// 取得新創建的新線程中的call()方法返回的結果
int sum = ft.get();
System.out.println("sum = " + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
需要特別注意的是:不能對同一線程對象兩次調用start()方法。原因是threadStatus的在一次調用後值就變化了,再次進入的時候通過判斷threadStatus的值從而產生異常。