日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Java四种线程创建的思路

發(fā)布時(shí)間:2025/3/15 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java四种线程创建的思路 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、哪四種

傳統(tǒng)的是繼承thread類和實(shí)現(xiàn)runnable接口,java5以后又有實(shí)現(xiàn)callable接口和java的線程池獲得。 callable相比于runnable,多了返回值,拋出了異常。

二、繼承Thread類創(chuàng)建線程

Thread類本質(zhì)上是實(shí)現(xiàn)了Runnable接口的一個(gè)實(shí)例,代表一個(gè)線程的實(shí)例。啟動(dòng)線程的唯一方法就是通過Thread類的start()實(shí)例方法。start()方法是一個(gè)native方法,它將啟動(dòng)一個(gè)新線程,并執(zhí)行run()方法。我們可以通過覆蓋run()方法達(dá)到自定義。

class MyThread extends Thread {@Overridepublic void run() {System.out.println("MyThread.run()");}public static void main(String[] args) throws InterruptedException {MyThread myThread1 = new MyThread();MyThread myThread2 = new MyThread();myThread1.start();myThread2.start();} }

步驟:

1.繼承 Thread 類 2.覆蓋 run() 方法 3.直接調(diào)用 Thread.start() 執(zhí)行

三、實(shí)現(xiàn)Runnable接口創(chuàng)建線程

Runnable是一個(gè)函數(shù)式接口,如果自己的類已經(jīng)extends另一個(gè)類,無法直接extends Thread,此時(shí),可以實(shí)現(xiàn)一個(gè)Runnable接口。

public class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("this is runnable");}public static void main(String[] args) throws InterruptedException {MyRunnable myRunnable = new MyRunnable();MyRunnable myRunnable1 = new MyRunnable();Thread thread=new Thread(myRunnable);Thread thread1=new Thread(myRunnable1);thread.start();thread1.start();thread.join();thread1.join();} }

步驟:

1.實(shí)現(xiàn)Runnable接口 2.獲取實(shí)現(xiàn)Runnable接口的實(shí)例,作為參數(shù),創(chuàng)建Thread實(shí)例 3.執(zhí)行 Thread#start() 啟動(dòng)線程

四、實(shí)現(xiàn)Callable接口通過FutureTask包裝器來創(chuàng)建Thread線程

Callable也是函數(shù)式接口,相比于Runnable接口而言,會(huì)有個(gè)返回值

class callAble implements Callable<Integer> {@Overridepublic Integer call() throws Exception {TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"---Callable.call()");return 200;} } public class MyCallable {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask<Integer> ft2 = new FutureTask<Integer>(new callAble());FutureTask<Integer> ft =new FutureTask<Integer>(()->{TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"---Callable.call()");return 1024;});new Thread(ft,"zhang3").start();new Thread(ft2,"li4").start();System.out.println(Thread.currentThread().getName());System.out.println(ft.get());System.out.println(ft2.get());} } //main //zhang3---Callable.call() //li4---Callable.call() //1024 //200

步驟

1.實(shí)現(xiàn)Callable接口 2.以Callable的實(shí)現(xiàn)類為參數(shù),創(chuàng)建FutureTask實(shí)例//搭建runnable與callable之間的橋梁 3.將FutureTask作為Thread的參數(shù),創(chuàng)建Thread實(shí)例 4.通過 Thread#start 啟動(dòng)線程 5.通過 FutreTask#get() 阻塞獲取線程的返回值

五、runnable與callable的異同

Callable接口和Runnable接口相似,區(qū)別就是Callable需要實(shí)現(xiàn)call方法,而Runnable需要實(shí)現(xiàn)run方法;并且,call方法還可以返回任何對象,無論是什么對象,JVM都會(huì)當(dāng)作Object來處理。但是如果使用了泛型,我們就不用每次都對Object進(jìn)行轉(zhuǎn)換了。

Runnable.run()

Callable.call()

不同之處:

1.Callable可以返回一個(gè)類型V,而Runnable不可以
2.Callable能夠拋出checked exception,而Runnable不可以。
3.Runnable是自從java1.1就有了,而Callable是1.5之后才加上去的
4.Callable和Runnable都可以應(yīng)用于executors。而Thread類只支持Runnable.

上面只是簡單的不同,其實(shí)這兩個(gè)接口在用起來差別還是很大的。Callable與executors聯(lián)合在一起,在任務(wù)完成時(shí)可立刻獲得一個(gè)更新了的Future。而Runable卻要自己處理。

六、關(guān)于FutureTask接口

FutureTask接口,一般都是取回Callable執(zhí)行的狀態(tài)用的。其中的主要方法:

與callable相關(guān)的構(gòu)造方法:

使用FutrueTask的情景:

  • 在主線程中需要執(zhí)行比較耗時(shí)的操作時(shí),但又不想阻塞主線程時(shí),可以把這些作業(yè)交給Future對象在后臺(tái)完成,
    當(dāng)主線程將來需要時(shí),就可以通過Future對象獲得后臺(tái)作業(yè)的計(jì)算結(jié)果或者執(zhí)行狀態(tài)。
  • 一般FutureTask多用于耗時(shí)的計(jì)算,主線程可以在完成自己的任務(wù)后,再去獲取結(jié)果。
  • 僅在計(jì)算完成時(shí)才能檢索結(jié)果;如果計(jì)算尚未完成,則阻塞 get 方法。一旦計(jì)算完成,就不能再重新開始或取消計(jì)算。get方法而獲取結(jié)果只有在計(jì)算完成時(shí)獲取,否則會(huì)一直阻塞直到任務(wù)轉(zhuǎn)入完成狀態(tài),
    然后會(huì)返回結(jié)果或者拋出異常。
  • 只計(jì)算一次,get方法放到最后,可以使用isDone方法,判斷是否計(jì)算完,再獲取

runnable不關(guān)心返回,只管執(zhí)行,也不用告訴我完成沒有,我不care,您自己隨便玩,所以一般使用就是new Thread(new Runnable() { public void run() {...} }).start()換成JDK8的 lambda表達(dá)式就更簡單了 new Thread(() -> {}).start();
callbale就悲催一點(diǎn),沒法隨意了,必須等待返回的結(jié)果,但是這個(gè)線程的狀態(tài)我又控制不了,怎么辦?只能借助FutrueTask(相同的操作只會(huì)執(zhí)行一次,以后的線程再調(diào)用,直接返回),所以一般可以看到使用方式如下:

FutureTask<Integer> ft =new FutureTask<Integer>(()->{TimeUnit.SECONDS.sleep(3);System.out.println(Thread.currentThread().getName()+"---Callable.call()");return 1024;});new Thread(ft,"zhang3").start();System.out.println(Thread.currentThread().getName());while (!ft.isDone()){System.out.println("-----wait");}System.out.println(ft.get());

七、使用線程池創(chuàng)建線程(三大方法,七大參數(shù),四大策略)

線程池的優(yōu)勢:
線程池做的工作只要是控制運(yùn)行的線程數(shù)量,處理過程中將任務(wù)放入隊(duì)列,然后在線程創(chuàng)建后啟動(dòng)這些任務(wù),如果線程數(shù)量超過了最大數(shù)量,超出數(shù)量的線程排隊(duì)等候,等其他線程執(zhí)行完畢,再從隊(duì)列中取出任務(wù)來執(zhí)行。
它的主要特點(diǎn)為:線程復(fù)用;控制最大并發(fā)數(shù);管理線程。

  • 第一:降低資源消耗。通過重復(fù)利用已創(chuàng)建的線程降低線程創(chuàng)建和銷毀造成的銷耗。
  • 第二:提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等待線程創(chuàng)建就能立即執(zhí)行。
  • 第三:提高線程的可管理性。線程是稀缺資源,如果無限制的創(chuàng)建,不僅會(huì)銷耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,使用線程池可以進(jìn)行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。

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

八、線程池底層工作原理

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

九、Java通過Executors提供的線程池

  • newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
//這種方式創(chuàng)建的都是非核心線程,而且最大線程數(shù)為Interge的最大值,空閑線程存活時(shí)間是1分鐘。 //如果有大量耗時(shí)的任務(wù),則不適該創(chuàng)建方式, 它只適用于生命周期短的任務(wù)。 public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,//注意所使用的阻塞隊(duì)列new SynchronousQueue<Runnable>());}
  • newFixedThreadPool 創(chuàng)建一個(gè)定長線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待。
//創(chuàng)建一個(gè)定長線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待。public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,//注意所使用的阻塞隊(duì)列new LinkedBlockingQueue<Runnable>());}
  • newSingleThreadExecutor創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行。
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,//注意所使用的阻塞隊(duì)列new LinkedBlockingQueue<Runnable>()));}
  • newScheduledThreadPool 創(chuàng)建一個(gè)定長線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue()); }

可以看出,上面的類都使用ThreadPoolExecutor實(shí)現(xiàn):

//主要參數(shù):- 1、corePoolSize:線程池中的常駐核心線程數(shù)- 2、maximumPoolSize:線程池中能夠容納同時(shí) 執(zhí)行的最大線程數(shù),此值必須大于等于1- 3、keepAliveTime:多余的空閑線程的存活時(shí)間 當(dāng)前池中線程數(shù)量超過corePoolSize時(shí),當(dāng)空閑時(shí)間達(dá)到keepAliveTime時(shí),多余線程會(huì)被銷毀直到 只剩下corePoolSize個(gè)線程為止- 4、unit:keepAliveTime的單位- 5、workQueue:任務(wù)隊(duì)列,被提交但尚未被執(zhí)行的任務(wù)- 6、threadFactory:表示生成線程池中工作線程的線程工廠, 用于創(chuàng)建線程,一般默認(rèn)的即可- 7、handler:拒絕策略,表示當(dāng)隊(duì)列滿了,并且工作線程大于 等于線程池的最大線程數(shù)(maximumPoolSize)時(shí)如何來拒絕請求執(zhí)行的runnable的策略 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

十、線程池的拒絕策略

  • 是什么
    等待隊(duì)列已經(jīng)排滿了,再也塞不下新任務(wù)了。同時(shí),線程池中的max線程也達(dá)到了,無法繼續(xù)為新任務(wù)服務(wù)。這個(gè)是時(shí)候我們就需要拒絕策略機(jī)制合理的處理這個(gè)問題。
  • JDK內(nèi)置的拒絕策略
1.AbortPolicy:直接拋出RejectedExecutionException異常阻止系統(tǒng)正常運(yùn)行(默認(rèn)) 2.CallerRunsPolicy:“調(diào)用者運(yùn)行”一種調(diào)節(jié)機(jī)制,該策略既不會(huì)拋棄任務(wù),也不會(huì)拋出異常,而是將某些任務(wù)回退到調(diào)用者,從而降低新任務(wù)的流量。 3.DiscardOldestPolicy:拋棄隊(duì)列中等待最久的任務(wù),然后把當(dāng)前任務(wù)加人隊(duì)列中嘗試再次提交當(dāng)前任務(wù)。 4.DiscardPolicy:該策略默默地丟棄無法處理的任務(wù),不予任何處理也不拋出異常。如果允許任務(wù)丟失,這是最好的一種策略。 //以上內(nèi)置拒絕策略均實(shí)現(xiàn)了RejectedExecutionHandle接口

ThreadPoolExecutor 有四個(gè)構(gòu)造方法,實(shí)際上我們一般常用第一個(gè)構(gòu)造方法,它默認(rèn)指定AbortPolicy ()為拒絕策略

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);} public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);} public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);} public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}
  • 工作中用哪個(gè)線程池

一個(gè)都不用,我們工作中只能使用自定義的

如下代碼:

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,//corePoolSize5,//mainumPoolSize3L,//keepAliveTimsTimeUnit.SECONDS,//keepAliveTime單位new ArrayBlockingQueue<Runnable>(3),//任務(wù)隊(duì)列,被提交但尚未被執(zhí)行的任務(wù)Executors.defaultThreadFactory(),//生成線程池中工作線程的線程工廠,一般默認(rèn)new ThreadPoolExecutor.DiscardPolicy()//拒接策略);//10個(gè)顧客請求try {for (int i = 1; i <= 10; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "\t 辦理業(yè)務(wù)");});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}}private static void threadPool() {//固定數(shù)的線程池,一池五線 // ExecutorService threadPool = Executors.newFixedThreadPool(5); //一個(gè)銀行網(wǎng)點(diǎn),5個(gè)受理業(yè)務(wù)的窗口 // ExecutorService threadPool = Executors.newSingleThreadExecutor(); //一個(gè)銀行網(wǎng)點(diǎn),1個(gè)受理業(yè)務(wù)的窗口ExecutorService threadPool = Executors.newCachedThreadPool(); //一個(gè)銀行網(wǎng)點(diǎn),可擴(kuò)展受理業(yè)務(wù)的窗口//10個(gè)顧客請求try {for (int i = 1; i <= 10; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "\t 辦理業(yè)務(wù)");});}} catch (Exception e) {e.printStackTrace();} finally {threadPool.shutdown();}} }

總結(jié)

以上是生活随笔為你收集整理的Java四种线程创建的思路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。