線程與進程之間的關係及爲何須要多線程放到進程相關文章中進行詳解java
查詢Thread的源碼能夠看到,內部有一個State的枚舉類,內部有線程的六個狀態web
public enum State { //線程新生 NEW, //運行 RUNNABLE, //阻塞 BLOCKED, //等待 死死的等 須要別人喚醒 WAITING, //超時等待 自動啓動 TIMED_WAITING, //終止 TERMINATED; }
狀態的互相切換
繼承Thread類
public class Start { public static void main(String[] args) { MyThread thread1 = new MyThread("thread#1"); MyThread thread2 = new MyThread("thread#2"); thread1.start(); thread2.start(); } } class MyThread extends Thread{ public MyThread(String name) { super(name); } @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName() + "print:"+ i); } } }
實現Runnable接口
public class Start { public static void main(String[] args) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); new Thread(thread1).start(); new Thread(thread2).start(); } } class MyThread implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "print:"+ i); } } }
public class Start { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "print:"+ i); } } },"A").start(); //使用lambda表達式 new Thread(()->{ for (int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName() + "print:"+ i); } },"B").start(); } }
實現Callable接口
咱們從文檔能夠看出,Callable接口與Runnable接口的不一樣:數據庫
那麼Callable接口怎樣才能開啓線程呢?緩存
能夠發現Runnable有個FutureTask的實現類,這個類可使Runnable接口返回結果,也能夠執行Callable接口多線程
public class CallableTest { public static void main(String[] args) throws ExecutionException, InterruptedException { //new Thread(new Runnable() ).start(); // V 就是返回值的類型 //new Thread(new FutureTask<V>(callable)).start; Mythread mythread = new Mythread(); FutureTask futureTask = new FutureTask(mythread);//適配類 new Thread(futureTask, "A").start(); new Thread(futureTask, "B").start();//因爲結果會緩存,提升效率,因此只會打印一個call Integer o = (Integer)futureTask.get(); //獲取返回結果,這個get 方法可能會產生阻塞,會等待線程處理結果的方程。 //或者使用異步通訊 來處理 System.out.println(o); } } class Mythread implements Callable<Integer>{ @Override public Integer call() { System.out.println("call()"); return 1024; } }
兩個均可以讓線程陷入等待,他們的區別以下:異步
來自不一樣的類ide
關於鎖的釋放this
使用範圍是不一樣的spa
是否須要捕獲異常線程
利用一個常見的生產者消費者模式來演示wait(),notify()
public class PC { public static void main(String[] args) { Data data = new Data(); new Thread(()->{ for (int i = 0; i < 50; i++) { try { data.produce(); } catch (InterruptedException e) { e.printStackTrace(); } } },"A").start(); new Thread(()->{ for (int i = 0; i < 50; i++) { try { data.consume(); } catch (InterruptedException e) { e.printStackTrace(); } } },"B").start(); } } class Data{ private static int number = 0; void produce() throws InterruptedException { synchronized (this) { if (number != 0) { this.wait(); } number++; System.out.println(Thread.currentThread().getName() + "生產" + number); this.notify(); } } synchronized void consume() throws InterruptedException { synchronized (this){ if (number == 0){ this.wait(); } number--; System.out.println(Thread.currentThread().getName() + "消費" + number); this.notify(); } } }
以上代碼能夠順利讓線程交替執行,可是有一個地方在多線程的時候會出現BUG。
在有着更多的線程時,要注意wait條件的一個判斷。
一、禮讓線程,讓當前正在執行的線程暫停,但不阻塞
二、將線程從運行狀態轉爲就緒狀態
三、讓CPU從新調度,禮讓不必定成功
public class Yield { public static void main(String[] args) { MyYield myYield = new MyYield(); new Thread(myYield, "A").start(); new Thread(myYield, "B").start(); } } class MyYield implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + ":線程執行"); Thread.yield(); System.out.println(Thread.currentThread().getName() + ":線程中止"); } }
該代碼會出現禮讓成功與禮讓不成功的狀況,能夠本身嘗試一下。
等待此線程執行完以後,再執行其餘線程
public class JoinTest implements Runnable { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("插隊開始。。。" + i); } } public static void main(String[] args) throws InterruptedException { JoinTest joinTest = new JoinTest(); Thread thread = new Thread(joinTest); thread.start(); for (int i = 0; i < 1000; i++) { if (i == 200){ thread.join(); } System.out.println("main..." + i); } } }
一、使用線程標誌位讓線程中止下來
public class StopTest implements Runnable { private boolean flag = false; @Override public void run() { int i = 0; while (!flag){ System.out.println("run..." + i++); } } public static void main(String[] args) throws InterruptedException { StopTest stopTest = new StopTest(); Thread thread = new Thread(stopTest); thread.start(); for (int i = 0; i < 15; i++) { System.out.println("main"+i); Thread.sleep(10); if (i == 8){ stopTest.stop(); System.out.println("線程中止"); } } } public void stop(){ this.flag = true; } }
二、使用interrupt方法中斷線程
利用後兩種能夠判斷狀態(就是下面圖片中的後兩種方法)
線程中止-拋異常法
先sleep,後interrupt
先interrupt後sleep
三、使用stop()方法(棄用)
爲何棄用stop:
線程優先度從1-10,可是仍然仍是CPU說的算