1. 程式人生 > >多執行緒基礎知識

多執行緒基礎知識

一、什麼是多執行緒

二、多執行緒建立的幾種方式

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()方法,該執行緒結束生命週期。