1. 程式人生 > >java多線程(一)-五種線程創建方式

java多線程(一)-五種線程創建方式

timer 建議 ted 資源 all 巴巴 並發編程 lex 自動調用

簡單使用示例

Java 提供了三種創建線程的方法:

  • 通過實現 Runnable 接口;
  • 通過繼承 Thread 類本身;
  • 通過 Callable 和 Future 創建線程。

還有

  • 定時器
  • 線程池

下面第一個類給出了四種創建方式,第二個類是定時器示例。

public class ThreadStartTest {
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.print("主線程(main)0啟動!");

        //實例化線程對象
        Thread_1 thread_1 = new Thread_1();
        //調用start()方法開啟線程,然後會自動調用run()方法
        thread_1.start();
        
        //將實現Runnable接口對象實例化提交給Thread構造器(構造方法)
        Thread thread_2 = new Thread(new Thread_2());
        thread_2.start();

        //callable接口可以返回值,但必須用submit()提交
        ExecutorService execu = Executors.newCachedThreadPool();
        Future<String> result  = execu.submit(new TastWithResult());
        System.out.println(result.get());
        execu.shutdown();

        //線程池
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new Thread_2());
        exec.shutdown();

        //main線程
        for(int i=0;i<5;i++) {
            //等同於Thread.sleep(2000);
            TimeUnit.MILLISECONDS.sleep(2000);
            System.out.print("0");
        }
    }
}
/**
 *  繼承Thread類,重寫run方法
 */
class Thread_1 extends Thread {
    @Override
    public void run() {
        System.out.print("線程1啟動!");
        for(int i=0;i<5;i++) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print("1");
        }
    }
}

/**
 * 實現Runnable接口
 */
class Thread_2 implements Runnable{
    @Override
    public void run() {
        System.out.print("線程2啟動!");
        for(int i=0;i<5;i++) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print("2");
        }
    }
}

class TastWithResult implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "可以返回值啦!";
    }
}

②定時器Timer

public class TimerTest {

    public static void main(String[] args) throws InterruptedException {
        Timer timer = new Timer();

        //前一次執行程序結束後 2000ms 後開始執行下一次程序(循環)
        timer.schedule(new TimerTask(){
            @Override
            public void run(){
                System.out.println("Task1");
            }
        },0,2000);
        //延遲1000ms執行程序
        timer.schedule(new TimerTask(){
            @Override
            public void run(){
                System.out.println("Task2");
            }
        },1000);
        //前一次程序執行開始 後 2000ms後開始執行下一次程序(循環)
        timer.scheduleAtFixedRate(new TimerTask(){
            @Override
            public void run(){
                System.out.println("Task3");
            }
        },0,2000);
        Thread.sleep(10*1000);
        timer.cancel();
    }
}

如果你想詳細的了解一下Timer內部實現,可以參考下面的文章

Time類的使用和源碼分析-小淘氣兒

說明

在《阿裏巴巴java開發手冊中》有這樣一條:

3. 【強制】線程資源必須通過線程池提供,不允許在應用中自行顯式創建線程。

說明:使用線程池的好處是減少在創建和銷毀線程上所消耗的時間以及系統資源的開銷,解決資源不足的問題。如果不使用線程池,有可能造成系統創建大量同類線程而導致消耗完內存或
者“過度切換”的問題。

所以建議使用線程池。

4. 【強制】線程池不允許使用 Executors 去創建,而是通過 ThreadPoolExecutor 的方式,這樣
的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
說明:Executors 返回的線程池對象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允許的請求隊列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允許的創建線程數量為 Integer.MAX_VALUE,可能會創建大量的線程,從而導致 OOM。

又因為有該建議,所以需要對線程池稍微深入了解使用。可以參考下面這篇文章。

Java並發編程:線程池的使用-海子

java多線程(一)-五種線程創建方式