總覽
- Java中的進程和線程
- 運行一個程序會產生一個進程,進程包含至少一個線程(主線程)
- 每個進程對應一個JVM實例,多個線程共享JVM裏的堆
- 主線程可以創建子線程,主線程原則上要後於子線程完成執行(各種關閉動作在主線程中執行)
java線程(Thread)
-
Thread的
start()
和run()
- 調用
start()
會創建一個新的子進程並啓動,run()
只是Threa對象的普通方法調用
注:由源碼可得,start()
會創建一個線程,然後去執行run()
方法裏的內容 - Java線程創建關係圖
- 調用
-
Thread
和Runnable
Thread
是類,Runnable
是接口Thread
類實現了Runnable
接口Runnable
只有一個抽象run()
方法(Runnable
不具有多線程的特性)
-
java線程的創建
- 繼承
Thread
類,並重寫run()
方法(線程中的邏輯在run()
方法中實現)public class MyThread extends Thread { private String name; public MyThread(String name){ this.name = name; } @Override public void run(){ for(int i = 0 ; i < 10 ; i ++){ System.out.println("Thread start : " + this.name + ",i= " + i); } } } public class ThreadDemo { public static void main(String[] args) { MyThread mt1 = new MyThread("Thread1"); mt1.start(); } }
- 實現
Runnable
接口
原理:Thread
帶參構造函數中,可以傳遞Runnable
,且調用Thread
的run()
方法會調用Runnable
中的run()
方法
public class MyRunnable implements Runnable { private String name; public MyRunnable(String name){ this.name = name; } @Override public void run(){ for(int i = 0 ; i < 10 ; i ++){ System.out.println("Thread start : " + this.name + ",i= " + i); } } } public class RunnableDemo { public static void main(String[] args) throws InterruptedException { MyRunnable mr1 = new MyRunnable("Runnable1"); Thread t1 = new Thread(mr1); t1.start(); } }
- 補充:給
run()
方法傳參- 構造方法傳參
- 成員變量傳參
- 回調函數傳參
- 繼承
-
java線程返回值的處理
- 主線程等待法
Thread.currentThread().sleep(500);
- 使用
Thread
類的join()
阻塞當前線程以等待子線程處理完畢public class CycleWait implements Runnable{ private String value; public void run() { try { Thread.currentThread().sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } value = "we have data now"; } public static void main(String[] args) throws InterruptedException { CycleWait cw = new CycleWait(); Thread t = new Thread(cw); t.start(); // while (cw.value == null){ // Thread.currentThread().sleep(100); // } t.join(); System.out.println("value : " + cw.value); } }
- 通過
Callable
接口實現:通過FutureTask
或者線程池
獲取FutureTask
注:FutureTask
實現了Runnable
- 判斷
Callable
中的call
方法是否執行完畢 - 若
call
方法執行完畢,則返回,否則阻塞當前進程
- 帶參
get
,增加了超時機制
//實現callable public class MyCallable implements Callable<String> { @Override public String call() throws Exception{ String value="test"; System.out.println("Ready to work"); Thread.currentThread().sleep(5000); System.out.println("task done"); return value; } } //通過FutureTask完成等待 public class FutureTaskDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> task = new FutureTask<String>(new MyCallable()); new Thread(task).start(); if(!task.isDone()){ System.out.println("task has not finished, please wait!"); } System.out.println("task return: " + task.get()); } } //通過線程池等待 public class ThreadPoolDemo { public static void main(String[] args) { ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); Future<String> future = newCachedThreadPool.submit(new MyCallable()); if(!future.isDone()){ System.out.println("task has not finished, please wait!"); } try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { newCachedThreadPool.shutdown(); } } }
sleep
和wait
方法sleep
sleep
是Thread
類的方法- 可以在任何地方調用
sleep
方法只會讓出CPU,不會釋放鎖
wait
wait
是Object
類中定義的方法- 只能在
synchronized
方法或synchronized
塊中使用 wait
方法會讓出CPU,也會釋放已經佔有的同步鎖
public class WaitSleepDemo { public static void main(String[] args) { final Object lock = new Object(); new Thread(new Runnable() { @Override public void run() { System.out.println("thread A is waiting to get lock"); synchronized (lock){ try { System.out.println("thread A get lock"); Thread.sleep(20); System.out.println("thread A do wait method"); lock.wait(); System.out.println("thread A is done"); } catch (InterruptedException e){ e.printStackTrace(); } } } }).start(); try{ Thread.sleep(10); } catch (InterruptedException e){ e.printStackTrace(); } new Thread(new Runnable() { @Override public void run() { System.out.println("thread B is waiting to get lock"); synchronized (lock){ try { System.out.println("thread B get lock"); System.out.println("thread B is sleeping 10 ms"); Thread.sleep(10); lock.notifyAll(); Thread.yield(); Thread.sleep(2000); System.out.println("thread B is done"); } catch (InterruptedException e){ e.printStackTrace(); } } } }).start(); } }
- 線程的中斷
- 調用
interrupt()
通知線程中斷
- 線程中應該做的處理
public class InterruptDemo { public static void main(String[] args) throws InterruptedException { Runnable interruptTask = new Runnable() { @Override public void run() { int i = 0; try { //在正常運行任務時,經常檢查本線程的中斷標誌位,如果被設置了中斷標誌就自行停止線程 while (!Thread.currentThread().isInterrupted()) { Thread.sleep(100); // 休眠100ms i++; System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") loop " + i); } } catch (InterruptedException e) { //在調用阻塞方法時正確處理InterruptedException異常。(例如,catch異常後就結束線程。) System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") catch InterruptedException."); } } }; Thread t1 = new Thread(interruptTask, "t1"); System.out.println(t1.getName() +" ("+t1.getState()+") is new."); t1.start(); // 啓動“線程t1” System.out.println(t1.getName() +" ("+t1.getState()+") is started."); // 主線程休眠300ms,然後主線程給t1發“中斷”指令。 Thread.sleep(300); t1.interrupt(); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted."); // 主線程休眠300ms,然後查看t1的狀態。 Thread.sleep(300); System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now."); } }
- 調用
- 線程狀態圖
- 主線程等待法