欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java創(chuàng)建線程的4種方式集合(最新整理)

 更新時間:2025年04月01日 15:45:24   作者:The博宇  
在Java中,創(chuàng)建線程有多種方式,每種方式都有其適用場景和優(yōu)缺點,下面給大家分享java創(chuàng)建線程的4種方式,感興趣的朋友一起看看吧

在Java中,創(chuàng)建線程有多種方式,每種方式都有其適用場景和優(yōu)缺點。以下是四種常見的創(chuàng)建線程的方式:

一、方式一:繼承Thread類

這是最直觀的方式,通過創(chuàng)建一個新的類繼承Thread類,并重寫其run方法。

class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("數(shù)據(jù):" + i);
        }
    }
}
public class Demo01 {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        MyThread thread2 = new MyThread();
        thread2.start();
        for (int i = 10; i < 100; i++) {
            System.err.println("Main:" + i);
        }
    }
}

優(yōu)點:簡單直觀。

缺點:Java不支持多重繼承,因此如果一個類已經(jīng)繼承了另一個類,那么它就不能再繼承Thread類。

 二、方式二:實現(xiàn)Runnable接口創(chuàng)建線程目標類

這種方式更加靈活,因為它允許類繼承其他類的同時實現(xiàn)Runnable接口。

class A implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}
public class Demo03 {
    public static void main(String[] args) {
        A a = new A();
        new Thread(a).start();
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }).start();
        for (int i = 0; i < 1000; i++) {
            System.err.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

優(yōu)點:避免了Java單繼承的限制,可以更容易地擴展功能。

缺點:需要手動管理線程的生命周期。

 三、使用Callable和FutureTask創(chuàng)建線程

Callable接口與Runnable類似,但它可以返回值并拋出異常。

class MyCall implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 200;
    }
}
public class Demo08 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new MyCall());
        new Thread(futureTask, "計算線程").start();
        Integer i = futureTask.get();
        System.out.println(i);
    }
}

優(yōu)點:可以返回值和拋出異常。

缺點:使用起來比Runnable復雜,需要配合FutureTask使用。

通過FutureTask類和Callable接口的聯(lián)合使用可以創(chuàng)建能夠獲取異步執(zhí)行結(jié)果的線程,具體步驟如下:

(1) 創(chuàng)建一個Callable接口的實現(xiàn)類,并實現(xiàn)其call()方法,編寫好異步執(zhí)行的具體邏輯,可以有返回值。

(2) 使用Callable實現(xiàn)類的實例構造一個FutureTask實例。

(3) 使用FutureTask實例作為Thread構造器的target入?yún)?,構造新的Thread線程實例。

(4) 調(diào)用Thread實例的start()方法啟動新線程,啟動新線程的run()方法并發(fā)執(zhí)行。其內(nèi)部的執(zhí)行過程為:啟動Thread實例的run()方法并發(fā)執(zhí)行后,會執(zhí)行FutureTask實例的run()方法,最終會并發(fā)執(zhí)行Callable實現(xiàn)類的call()方法。

(5) 調(diào)用FutureTask對象的get()方法阻塞性地獲得并發(fā)線程的執(zhí)行結(jié)果。

按照以上步驟,通過Callable接口和Future接口相結(jié)合創(chuàng)建多線程,實例如下:

創(chuàng)建一個Callable接口的實現(xiàn)類:

public class CallableTaskDemo implements Callable {
    // 編寫好異步執(zhí)行的具體邏輯,可以有返回值。
    // (Runnable接口中的run()方法是沒有返回值得,Callable接口的call()方法有返回值)
    @Override
    public Long call() throws Exception {
        Long startTime = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName()+" 線程開始運行");
        Thread.sleep(1000);
        for(int i=0;i<100000000;i++){
            int j = i*10000;
        }
        Long endTime = System.currentTimeMillis();
        Long used = endTime-startTime;
        System.out.println(Thread.currentThread().getName()+" 線程結(jié)束運行");
        return used;
    }
}

 在這個例子中有兩個線程:一個是執(zhí)行main()方法的主線程,叫作main;另一個是main線程通過thread.start()方法啟動的業(yè)務線程,叫作callableTaskThread。該線程是一個包含F(xiàn)utureTask任務作為target的Thread線程。

public class CreateDemo {
    public static void main(String[] args) throws InterruptedException {
        CallableTaskDemo callableTaskDemo = new CallableTaskDemo();
        FutureTask<Long> futureTask = new FutureTask<Long>(callableTaskDemo);
        Thread thread = new Thread(futureTask,"callableTaskThread");
        thread.start();
        Thread.sleep(500);
        System.out.println("main線程執(zhí)行一會");
        for(int i=0;i<100000000/2;i++){
            int j = i*10000;
        }
        // 獲取并發(fā)任務的執(zhí)行結(jié)果
        try {
            System.out.println(thread.getName()+" 線程占用時間:"+futureTask.get());
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

main線程通過thread.start()啟動callableTaskThread線程之后,會繼續(xù)自己的事情,callableTaskThread線程開始并發(fā)執(zhí)行。

callableTaskThread線程首先執(zhí)行的是thread.run()方法,然后在其中會執(zhí)行到其target(futureTask任務)的run()方法;接著在這個futureTask.run()方法中會執(zhí)行futureTask的callable成員的call()方法,這里的callable成員(ReturnableTask實例)是通過FutureTask構造器在初始化時傳遞進來的、自定義的Callable實現(xiàn)類的實例。

說明:
Callable 接口:Callable 是一個泛型接口,call() 方法中定義了線程的任務,并返回一個結(jié)果。
Future 接口:Future 表示一個異步計算的結(jié)果,使用 get() 方法可以獲取線程執(zhí)行的結(jié)果。
ExecutorService:通常與 ExecutorService 結(jié)合使用,可以更好地管理線程池和任務。
優(yōu)點:
返回結(jié)果:Callable 可以返回執(zhí)行結(jié)果,而 Runnable 不能。
異常處理:Callable 可以拋出受檢查的異常,便于處理復雜任務中的錯誤。
線程池支持:與 ExecutorService 結(jié)合,可以實現(xiàn)靈活的線程管理。
缺點:
相對復雜:相比 Runnable 和 Thread,Callable 和 Future 的使用稍微復雜一些,特別是涉及到線程池的管理。

 四、使用線程池

線程池是一種更加高效的方式來管理線程,它可以復用線程,減少創(chuàng)建和銷毀線程的開銷。

第一種:使用自帶的API實現(xiàn)

Java中的線程池是通過Executor框架實現(xiàn)的,該框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor這幾個類。

經(jīng)常使用的線程池做法:
1、Executors.newFixedThreadPool(int)

執(zhí)行長期任務性能好,創(chuàng)建一個線程池,一池有N個固定的線程,有固定線程數(shù)的線程

newFixedThreadPool創(chuàng)建的線程池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue

2、Executors.newSingleThreadExecutor()

一個任務一個任務的執(zhí)行,一池一線程。

newSingleThreadExecutor 創(chuàng)建的線程池corePoolSize和maximumPoolSize值都是1,它使用的是LinkedBlockingQueue

3、Executors.newCachedThreadPool()

執(zhí)行很多短期異步任務,線程池根據(jù)需要創(chuàng)建新線程,但在先前構建的線程可用時將重用它們。可擴容,遇強則強。

newCachedThreadPool創(chuàng)建的線程池將corePoolSize設置為0,將maximumPoolSize設置為Integer.MAX_VALUE,它使用的是SynchronousQueue,也就是說來了任務就創(chuàng)建線程運行,當線程空閑超過60秒,就銷毀線程。

代碼演示: 

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyThreadPoolDemo {
    public static void main(String[] args) {
//       ExecutorService threadPool =  Executors.newFixedThreadPool(5); //一個銀行網(wǎng)點,5個受理業(yè)務的窗口
//       ExecutorService threadPool =  Executors.newSingleThreadExecutor(); //一個銀行網(wǎng)點,1個受理業(yè)務的窗口
       ExecutorService threadPool =  Executors.newCachedThreadPool(); //一個銀行網(wǎng)點,可擴展受理業(yè)務的窗口
        //10個顧客請求
        try {
            for (int i = 1; i <=10; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"\t 辦理業(yè)務");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

第二種:使用自定義線程池(面試的重點,不要輕視)

 1、corePoolSize:線程池中的常駐核心線程數(shù)
2、maximumPoolSize:線程池中能夠容納同時執(zhí)行的最大線程數(shù),此值必須大于等于1
3、keepAliveTime:多余的空閑線程的存活時間   
當前池中線程數(shù)量超過corePoolSize時,當空閑時間達到keepAliveTime時, 多余線程會被銷毀直到只剩下corePoolSize個線程為止。
4、unit:keepAliveTime的單位 
5、workQueue:任務隊列,被提交但尚未被執(zhí)行的任務  就是我們之前講的阻塞隊列
6、threadFactory:表示生成線程池中工作線程的線程工廠,用于創(chuàng)建線程,一般默認的即可
7、handler:拒絕策略,表示當隊列滿了,并且工作線程大于等于線程池的最大線程數(shù)(maximumPoolSize)時如何來拒絕。
請求執(zhí)行的runnable的策略

隊列和阻塞隊列?

阻塞隊列: 假如這個隊列中沒有數(shù)據(jù),會阻塞獲取數(shù)據(jù)的一方,如果隊列滿了,會阻塞存儲數(shù)據(jù)的一方。

線程池的拒絕策略:

AbortPolicy(默認):直接拋出RejectedExecutionException異常阻止系統(tǒng)正常運行。
CallerRunsPolicy:“調(diào)用者運行”一種調(diào)節(jié)機制,該策略既不會拋棄任務,也不會拋出異常,而是將某些任務回退到調(diào)用者,俗稱從哪兒來到哪兒去。
DiscardOldestPolicy:拋棄隊列中等待最久的任務,然后把當前任務加人隊列中嘗試再次提交當前任務。
DiscardPolicy:該策略默默地丟棄無法處理的任務,不予任何處理也不拋出異常。如果允許任務丟失,這是最好的一種策略。
 
以上內(nèi)置拒絕策略均實現(xiàn)了RejectedExecutionHandle接口

1、在創(chuàng)建了線程池后,線程池中的線程數(shù)為零。
2、當調(diào)用execute()方法添加一個請求任務時,線程池會做出如下判斷:
  2.1如果正在運行的線程數(shù)量小于corePoolSize,那么馬上創(chuàng)建線程運行這個任務;
  2.2如果正在運行的線程數(shù)量大于或等于corePoolSize,那么將這個任務放入隊列;
  2.3如果這個時候隊列滿了且正在運行的線程數(shù)量還小于maximumPoolSize,那么還是要創(chuàng)建非核心線程立刻運行這個任務;
  2.4如果隊列滿了且正在運行的線程數(shù)量大于或等于maximumPoolSize,那么線程池會啟動飽和拒絕策略來執(zhí)行。
3、當一個線程完成任務時,它會從隊列中取下一個任務來執(zhí)行。
4、當一個線程無事可做超過一定的時間(keepAliveTime)時,線程會判斷:
    如果當前運行的線程數(shù)大于corePoolSize,那么這個線程就被停掉。
    所以線程池的所有任務完成后,它最終會收縮到corePoolSize的大小。

 代碼演示:

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
/**
 * 線程池
 * Arrays
 * Collections
 * Executors
 */
public class MyThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                2L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(3),
                Executors.defaultThreadFactory(),
                //new ThreadPoolExecutor.AbortPolicy()
                //new ThreadPoolExecutor.CallerRunsPolicy()
                //new ThreadPoolExecutor.DiscardOldestPolicy()
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        //10個顧客請求
        try {
            for (int i = 1; i <= 10; i++) {
                threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 辦理業(yè)務");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}
總結(jié):

每種創(chuàng)建線程的方式都有其適用場景。在實際開發(fā)中,我們通常會根據(jù)需求選擇最合適的方式。例如,對于簡單的后臺任務,可以使用Runnable接口;對于需要返回結(jié)果的任務,可以使用Callable接口;而對于需要頻繁創(chuàng)建和銷毀線程的場景,使用線程池是更好的選擇。

到此這篇關于java創(chuàng)建線程的4種方式的文章就介紹到這了,更多相關java創(chuàng)建線程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Android APK反編譯圖文教程

    Android APK反編譯圖文教程

    學會反編譯比較關鍵,也是我們美化必須掌握技術,學會反編譯也是實現(xiàn)制作ROM的起步,ROM高手必然是反編譯高手這里有必要說一下,教程只是給你一個動手的那一個蹺板,教程不是萬能的,給了你基礎與啟發(fā),最重要的是我們能夠自主的進行創(chuàng)新與思考
    2016-04-04
  • Android自定義View實現(xiàn)支付寶咻一咻效果

    Android自定義View實現(xiàn)支付寶咻一咻效果

    這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)支付寶咻一咻效果的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • android studio實現(xiàn)計算器

    android studio實現(xiàn)計算器

    這篇文章主要為大家詳細介紹了android studio實現(xiàn)計算器的具體方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • android使用AsyncTask實現(xiàn)多線程下載實例

    android使用AsyncTask實現(xiàn)多線程下載實例

    這篇文章主要介紹了android使用AsyncTask實現(xiàn)多線程下載實例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • 新版Android studio導入微信支付和支付寶官方Demo問題解決大全

    新版Android studio導入微信支付和支付寶官方Demo問題解決大全

    這篇文章主要為大家詳細介紹了新版Android studio導入微信支付和支付寶官方Demo問題的解決大全,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 淺談android獲取設備唯一標識完美解決方案

    淺談android獲取設備唯一標識完美解決方案

    本篇文章主要介紹了淺談android獲取設備唯一標識完美解決方案,具有一定的參考價值,有興趣的可以了解一下
    2017-08-08
  • RN在Android打包發(fā)布App(詳解)

    RN在Android打包發(fā)布App(詳解)

    下面小編就為大家?guī)硪黄猂N在Android打包發(fā)布App(詳解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • 5個Android開發(fā)中比較常見的內(nèi)存泄漏問題及解決辦法

    5個Android開發(fā)中比較常見的內(nèi)存泄漏問題及解決辦法

    本文主要介紹了5個Android開發(fā)中比較常見的內(nèi)存泄漏問題及解決辦法,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • Android 日志工具(log)的使用方法

    Android 日志工具(log)的使用方法

    這篇文章主要介紹了Android 日志工具的使用方法的相關資料,需要的朋友可以參考下
    2017-07-07
  • Android使用GridView實現(xiàn)橫向滾動效果

    Android使用GridView實現(xiàn)橫向滾動效果

    這篇文章主要為大家詳細介紹了Android使用GridView實現(xiàn)橫向滾動效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07

最新評論