多執行緒(三) java中執行緒的簡單使用
阿新 • • 發佈:2018-12-17
java中,啟動執行緒通常是通過Thread或其子類通過呼叫start()方法啟動。
常見使用執行緒有兩種:實現Runnable介面和繼承Thread。而繼承Thread亦或使用TimerTask其底層依舊是實現了Runnabel介面。考慮到java的單繼承的限制,所以在開發過程中大部分情況在使用執行緒的時候是通過實現Runnabel介面或者Runnbel匿名類來實現的。
例如:
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()方法則會開啟一個新的執行緒執行。兩者的區別主要表現在前者是阻塞式的,而後者為非阻塞式。
例如:
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();之後,則如下
==== main ==== main ==== main ==== main ==== main ==== main
這裡之所以執行緒名稱為main是因為是在main執行緒中呼叫的run方法,所以打印出來的是===main。而thread.run();語句下面的迴圈則永遠不會執行,程式將會一直在run方法中迴圈下去。
那麼呼叫start方法,程式都做了些什麼呢?看一下底層實現。
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模型,這到後面再說。
=============================================
原文連結:多執行緒(三) java中執行緒的簡單使用 轉載請註明出處!
=============================================