Java?Runnable和Thread實(shí)現(xiàn)多線程哪個(gè)更好你知道嗎
實(shí)現(xiàn)Runnable 接口比繼承Thread 類的方式更好:
(1)可以避免由于Java單繼承帶來的局限性;
(2)可以實(shí)現(xiàn)業(yè)務(wù)執(zhí)行邏輯和數(shù)據(jù)資源的分離;
(3)可以與線程池配合使用,從而管理線程的生命周期;
1. 避免由于Java單繼承帶來的局限性
如果異步邏輯所在類已經(jīng)繼承了一個(gè)基類,就沒有辦法再繼承Thread類。比如,當(dāng)一個(gè)Dog類繼承了Pet類,再要繼承Thread類就不行了。所以在已經(jīng)存在繼承關(guān)系的情況下,只能使用實(shí)現(xiàn)Runnable接口的方式。
public class ThreadTask extends Thread { // 線程的執(zhí)行體 @Override public void run() { System.out.println("線程執(zhí)行的任務(wù)"); } }
public class RunnableTask implements Runnable { // 線程的執(zhí)行體 @Override public void run() { System.out.println("線程執(zhí)行的任務(wù)"); } }
2. 可以實(shí)現(xiàn)業(yè)務(wù)執(zhí)行邏輯和數(shù)據(jù)資源的分離
邏輯和數(shù)據(jù)更好分離。通過實(shí)現(xiàn)Runnable接口的方法創(chuàng)建多線程更加適合同一個(gè)資源被多段業(yè)務(wù)邏輯并行處理的場(chǎng)景。在同一個(gè)資源被多個(gè)線程邏輯異步、并行處理的場(chǎng)景中,通過實(shí)現(xiàn)Runnable接口的方式設(shè)計(jì)多個(gè)target執(zhí)行目標(biāo)類可以更加方便、清晰地將執(zhí)行邏輯和數(shù)據(jù)存儲(chǔ)分離,更好地體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想。
注意:并不是繼承Thread類不能實(shí)現(xiàn)資源共享,而是沒有實(shí)現(xiàn)Runnable接口更方便,更清晰,他們兩的主要區(qū)別就是類和接口的區(qū)別,但是我們一般多用Runnable。
(1) 通過繼承Thread類的方式實(shí)現(xiàn)多線程,數(shù)據(jù)資源和業(yè)務(wù)執(zhí)行邏輯是耦合在一起的, 多個(gè)線程并發(fā)地完成各自的任務(wù),訪問各自的數(shù)據(jù)資源,而不是共享一份數(shù)據(jù)資源:
public class ThreadDemo extends Thread { // 數(shù)據(jù)資源 private int ticket = 3; // 業(yè)務(wù)執(zhí)行邏輯 @Override public void run() { for(int i=0;i<3;i++){ if(ticket>0){ System.out.println(Thread.currentThread().getName()+" 賣票--->"+ ticket--); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println(Thread.currentThread().getName()+" 線程運(yùn)行結(jié)束"); } public static void main(String[] args) throws InterruptedException { // 創(chuàng)建2個(gè)線程,分別去執(zhí)行線程體中的業(yè)務(wù)邏輯 Thread thread1 = new ThreadDemo(); thread1.start(); Thread thread2 = new ThreadDemo(); thread2.start(); Thread.sleep(1000); System.out.println("main線程運(yùn)行結(jié)束"); } }
多個(gè)線程并發(fā)地完成各自的任務(wù),訪問各自的數(shù)據(jù)資源:
Thread-0 賣票--->3 Thread-1 賣票--->3 main線程運(yùn)行結(jié)束 Thread-0 賣票--->2 Thread-1 賣票--->2 Thread-1 賣票--->1 Thread-0 賣票--->1 Thread-0 線程運(yùn)行結(jié)束 Thread-1 線程運(yùn)行結(jié)束
(2) 通過繼承Thread類可以實(shí)現(xiàn)資源共享:
public class ThreadTask { private int ticket = 3; public synchronized void saleTicket(){ for(int i=0;i<3;i++){ if(ticket>0){ System.out.println(Thread.currentThread().getName()+" 賣票--->"+ticket--); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println(Thread.currentThread().getName()+" 線程運(yùn)行結(jié)束"); } }
public class ThreadA extends Thread { ThreadTask threadTask ; public ThreadA(ThreadTask threadTask){ super(); this.threadTask = threadTask; } @Override public void run() { threadTask.saleTicket(); } }
public class ThreadB extends Thread { ThreadTask threadTask ; public ThreadB(ThreadTask threadTask){ super(); this.threadTask = threadTask; } @Override public void run() { threadTask.saleTicket(); } }
public class Main { public static void main(String[] args) throws InterruptedException { ThreadTask threadTask = new ThreadTask(); ThreadA t1 = new ThreadA(threadTask); ThreadB t2 = new ThreadB(threadTask); t1.start(); t2.start(); } }
執(zhí)行結(jié)果:
Thread-0 賣票--->3
Thread-1 賣票--->2
Thread-1 賣票--->1
Thread-0 線程運(yùn)行結(jié)束
Thread-1 線程運(yùn)行結(jié)束
(3) 通過實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)多線程,能更好地做到多個(gè)線程并發(fā)地完成同一個(gè)任務(wù),訪問同一份數(shù)據(jù)資源。多個(gè)線程的代碼邏輯可以方便地訪問和處理同一個(gè)共享數(shù)據(jù)資源 ,這樣可以將線程邏輯和業(yè)務(wù)數(shù)據(jù)進(jìn)行有效的分離,更好地體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)思想。
public class RunnableDemo{ public static class RunnableTask implements Runnable{ // 數(shù)據(jù)資源 private int ticket = 3; // 線程執(zhí)行體 @Override public synchronized void run() { for(int i=0;i<3;i++){ if(ticket>0){ System.out.println(Thread.currentThread().getName()+" 賣票--->"+ticket--); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println(Thread.currentThread().getName()+" 線程運(yùn)行結(jié)束"); } } public static void main(String[] args) { // 將這一個(gè)target作為參數(shù)傳給兩個(gè)線程,那么這兩個(gè)線程執(zhí)行的都是這個(gè)target的run()方法 Runnable target = new RunnableTask(); // 創(chuàng)建兩個(gè)線程執(zhí)行target的線程體 Thread thread1 = new Thread(target,"thread1"); thread1.start(); Thread thread2 = new Thread(target,"thread2"); thread2.start(); System.out.println("main線程運(yùn)行結(jié)束"); } }
多個(gè)線程并發(fā)地完成同一個(gè)任務(wù),訪問同一份數(shù)據(jù)資源:
main線程運(yùn)行結(jié)束
thread1 賣票--->3
thread1 賣票--->2
thread1 賣票--->1
thread1 線程運(yùn)行結(jié)束
thread2 線程運(yùn)行結(jié)束
3. 可以與線程池配合使用,從而管理線程的生命周期
實(shí)現(xiàn)Runnable接口來實(shí)現(xiàn)線程,執(zhí)行目標(biāo)類,更容易和線程池配合使用,異步執(zhí)行任務(wù)在大多數(shù)情況下是通過線程池去提交的,而很少通過創(chuàng)建一個(gè)新的線程去提交,所以更多的做法是,通過實(shí)現(xiàn)Runnable接口創(chuàng)建異步執(zhí)行任務(wù),而不是繼承Thread去創(chuàng)建異步執(zhí)行任務(wù)。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Maven打包跳過測(cè)試的實(shí)現(xiàn)方法
使用Maven打包的時(shí)候,可能會(huì)因?yàn)閱卧獪y(cè)試打包失敗,這時(shí)候就需要跳過單元測(cè)試。本文就介紹了Maven打包跳過測(cè)試的實(shí)現(xiàn)方法,感興趣的可以了解一下2021-06-06一文詳解SpringMVC中的@RequestMapping注解
@RequestMapping是一個(gè)用于映射HTTP請(qǐng)求到處理方法的注解,在Spring框架中使用,它可以用于控制器類和處理方法上,用來指定處理不同URL路徑的請(qǐng)求,并定義請(qǐng)求的方法等,本文小編將給大家詳細(xì)的介紹一下SpringMVC中的@RequestMapping注解,需要的朋友可以參考下2023-08-08java學(xué)習(xí)DongTai被動(dòng)型IAST工具部署過程
被動(dòng)型IAST被認(rèn)為是DevSecOps測(cè)試階段實(shí)現(xiàn)自動(dòng)化安全測(cè)試的最佳工具,而就在前幾天,洞態(tài)IAST正式開源了,這對(duì)于甲方構(gòu)建安全工具鏈來說,絕對(duì)是一個(gè)大利好2021-10-10JAVA開發(fā)環(huán)境Vs?code配置步驟詳解
這篇文章主要為大家介紹了JAVA開發(fā)環(huán)境Vs?code配置步驟詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04Spring Boot 2結(jié)合Spring security + JWT實(shí)現(xiàn)微信小程序登錄
這篇文章主要介紹了Spring Boot 2結(jié)合Spring security + JWT實(shí)現(xiàn)微信小程序登錄,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01深入解析Java的Struts框架中的控制器DispatchAction
這篇文章主要介紹了深入解析Java的Struts框架中的控制器DispatchAction,Struts是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12