java中,啓動線程一般是經過Thread或其子類經過調用start()方法啓動。
常見使用線程有兩種:實現Runnable接口和繼承Thread。而繼承Thread亦或使用TimerTask其底層依舊是實現了Runnabel接口。考慮到java的單繼承的限制,因此在開發過程當中大部分狀況在使用線程的時候是經過實現Runnabel接口或者Runnbel匿名類來實現的。
例如:html
package com.zpj.thread.blogTest; /** * Created by PerkinsZhu on 2017/8/11 16:42. */ public class ThreadTest { public static void main(String[] args) { ThreadTest threadTest = new ThreadTest(); //全部的這些啓動方式的執行體都是在run方法中完成的 threadTest.testLambda(); threadTest.testRunnableWithAnonymousRunnable(); threadTest.testRunnableWithAnonymousThread(); threadTest.testRunnable(); threadTest.testMyThread(); } public void testLambda() {//lambda表達式開啓線程 jdk1.8中的特性 new Thread(() -> System.out.println("i am lambda Thread....")).start(); } public void testRunnableWithAnonymousThread() {//匿名Thread類開啓線程 new Thread() { @Override public void run() { System.out.println("i am ThreadWithAnoymous"); } }.start(); } public void testRunnableWithAnonymousRunnable() {//匿名Runnable類開啓線程 Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("i am RunableWithAnoymous"); } }); thread.start(); } public void testRunnable() {//實現Runnable接口 MyRunnable runable = new MyRunnable(); Thread thread = new Thread(runable); thread.start(); } public void testMyThread() {//繼承自Thread MyThread thread = new MyThread(); thread.setName("MyThread"); thread.start(); } } class MyRunnable implements Runnable {//實現Runnable接口 @Override public void run() { System.out.println("i am MyRunnable"); } } class MyThread extends Thread {//繼承Thread @Override public void run() { System.out.println(" i am MyThread!!"); } }
注意,直接調用run()方法的方式執行線程體並未開啓新線程,只是在main方法中調用了一個普通方法而已。而使用start()方法則會開啓一個新的線程執行。二者的區別主要表如今前者是阻塞式的,然後者爲非阻塞式。java
例如:多線程
public void testStartAndRun(){ MyThread thread = new MyThread(); thread.setName("MyThread"); thread.start();//start啓動二者異步非阻塞運行 while (true){ System.out.println("---- "+Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } class MyThread extends Thread {//繼承Thread @Override public void run() { while(true){ System.out.println("=== "+Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
運行結果以下:異步
---- main
==== MyThread
---- main
==== MyThread
==== MyThread
---- main
==== MyThread
---- main
而把thread.start() 修改成thread.run();以後,則以下ide
==== main ==== main ==== main ==== main ==== main ==== main
這裏之因此線程名稱爲main是由於是在main線程中調用的run方法,因此打印出來的是===main。而thread.run();語句下面的循環則永遠不會執行,程序將會一直在run方法中循環下去。post
那麼調用start方法,程序都作了些什麼呢?看一下底層實現。this
public synchronized void start() { //驗證線程的狀態 if (threadStatus != 0) {//這裏的驗證涉及到線程不能重複啓動的問題,線程屢次調用start則會拋出該異常 throw new IllegalThreadStateException(); } //把該線程加入到線程組中 group.add(this); boolean started = false;//標識線程是否啓動成功 try { start0();//調用native方法啓動線程 該方法是阻塞的,程序等待其完成以後執行下面語句若是執行失敗則直接拋出異常進入finally。 started = true;//修改線程啓動狀態 } finally { try { if (!started) {//啓動失敗,則移出線程組 group.threadStartFailed(this); } } catch (Throwable ignore) { } } } private native void start0();//native方法啓動線程
經過Runnable啓動具備必定的侷限,執行線程沒有返回值,沒法捕獲異常。在有些特殊狀況下須要線程返回結果的時候就不太合適。這時能夠選擇Callable接口來完成。Callable涉及到Future模型,這到後面再說。url
=============================================spa
原文連接:多線程(三) java中線程的簡單使用 轉載請註明出處!線程
=============================================
-----end