多執行緒基礎知識
一、什麼是多執行緒
二、多執行緒建立的幾種方式
1、繼承Thread
thread是程式執行的一個執行緒,Java虛擬機器允許一個應用程式多執行緒同時執行,每個執行緒都有優先順序,優先順序高的比優先順序低的執行緒優先執行,每個執行緒有可能會被標記為守護執行緒。
//繼承Thread方式,重寫run()方法 public class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running"); } public static void main( String[] args ) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); thread1.start();//啟動執行緒thread1 thread2.start();//啟動執行緒thread2 } }
執行結果
Thread-1 is running Thread-0 is running
2、實現Runnable介面
/** * 實現Runnable介面 */ public class MyThread1 implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running"); } public static void main(String[] args) { MyThread1 myThread1 = new MyThread1(); Thread thread = new Thread(myThread1); thread.start(); } }
3、實現Callable介面
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; //實現Callable<V>介面,V為方法返回型別 public class CallableImpl implements Callable<Double> { @Override public Double call() throws Exception { Thread.sleep(1000); double result = Math.random(); System.out.println(Thread.currentThread().getName()+" is running !"); return result; } public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<Double> callable = new CallableImpl(); FutureTask<Double> future = new FutureTask<>(callable); //建立並啟動執行緒 new Thread(future).start(); //呼叫get()會阻塞主執行緒,否則不會阻塞 Double result = future.get(); System.out.println("result=" + result); System.out.println("main is running !"); } }
4、執行緒池
public class ExecutorThread { public static void main(String[] args) { //使用 guava 開源框架的 ThreadFactoryBuilder 給執行緒池的執行緒設定名字 ThreadFactory nameThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-pool-%d").build(); ExecutorService service = new ThreadPoolExecutor(4,10,0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(1024), nameThreadFactory, new ThreadPoolExecutor.AbortPolicy()); service.execute(()-> System.out.println(Thread.currentThread().getName() + " is running !")); service.execute(()-> System.out.println(Thread.currentThread().getName() + " is running !")); service.execute(()-> System.out.println(Thread.currentThread().getName() + " is running !")); service.execute(()-> System.out.println(Thread.currentThread().getName() + " is running !")); service.execute(()-> System.out.println(Thread.currentThread().getName() + " is running !")); service.shutdown(); } }
三、執行緒的生命週期
執行緒的五種基本狀態:
1)新建狀態(New):當執行緒物件建立後,執行緒進入新建狀態,如:Thread t = new Thread();
2)就緒狀態(Runnable):當呼叫執行緒物件的start()方法,即t.start(),執行緒就從新建狀態變為就緒狀態。處於就緒狀態的執行緒只是說執行緒已經做好了準備,隨時等待CPU排程執行,因此呼叫start()方法並不是說執行緒立即去執行,只是執行緒進入了一個可執行的狀態。
3)執行狀態(Running):當處於就緒狀態的執行緒獲得了CPU的排程執行後,此時執行緒進入執行狀態。
4)阻塞狀態(Blocked):處於執行狀態中的執行緒由於某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU呼叫以進入到執行狀態。根據阻塞產生的原因不同,阻塞狀態又可以分為三種:
1.等待阻塞:執行狀態中的執行緒執行wait()方法,使本執行緒進入到等待阻塞狀態;
2.同步阻塞 -- 執行緒在獲取synchronized同步鎖失敗(因為鎖被其它執行緒所佔用),它會進入同步阻塞狀態;
3.其他阻塞 -- 通過呼叫執行緒的sleep()或join()或發出了I/O請求時,執行緒會進入到阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入就緒狀態。
5)死亡狀態(Dead):執行緒執行完了或者因異常退出了run()方法,該執行緒結束生命週期。