Java?Runnable和Thread實(shí)現(xiàn)多線程哪個(gè)更好你知道嗎
實(shí)現(xiàn)Runnable 接口比繼承Thread 類的方式更好:
(1)可以避免由于Java單繼承帶來(lái)的局限性;
(2)可以實(shí)現(xiàn)業(yè)務(wù)執(zhí)行邏輯和數(shù)據(jù)資源的分離;
(3)可以與線程池配合使用,從而管理線程的生命周期;
1. 避免由于Java單繼承帶來(lái)的局限性
如果異步邏輯所在類已經(jīng)繼承了一個(gè)基類,就沒(méi)有辦法再繼承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ù)更好分離。通過(guò)實(shí)現(xiàn)Runnable接口的方法創(chuàng)建多線程更加適合同一個(gè)資源被多段業(yè)務(wù)邏輯并行處理的場(chǎng)景。在同一個(gè)資源被多個(gè)線程邏輯異步、并行處理的場(chǎng)景中,通過(guò)實(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)資源共享,而是沒(méi)有實(shí)現(xiàn)Runnable接口更方便,更清晰,他們兩的主要區(qū)別就是類和接口的區(qū)別,但是我們一般多用Runnable。
(1) 通過(guò)繼承Thread類的方式實(shí)現(xiàn)多線程,數(shù)據(jù)資源和業(yè)務(wù)執(zhí)行邏輯是耦合在一起的, 多個(gè)線程并發(fā)地完成各自的任務(wù),訪問(wèn)各自的數(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ù),訪問(wèn)各自的數(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) 通過(guò)繼承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) 通過(guò)實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)多線程,能更好地做到多個(gè)線程并發(fā)地完成同一個(gè)任務(wù),訪問(wèn)同一份數(shù)據(jù)資源。多個(gè)線程的代碼邏輯可以方便地訪問(wèn)和處理同一個(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ù),訪問(wèn)同一份數(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接口來(lái)實(shí)現(xiàn)線程,執(zhí)行目標(biāo)類,更容易和線程池配合使用,異步執(zhí)行任務(wù)在大多數(shù)情況下是通過(guò)線程池去提交的,而很少通過(guò)創(chuàng)建一個(gè)新的線程去提交,所以更多的做法是,通過(guò)實(shí)現(xiàn)Runnable接口創(chuàng)建異步執(zhí)行任務(wù),而不是繼承Thread去創(chuàng)建異步執(zhí)行任務(wù)。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
這么設(shè)置IDEA中的Maven,再也不用擔(dān)心依賴下載失敗了
今天給大家?guī)?lái)一個(gè)IDEA中Maven設(shè)置的小技巧.這個(gè)技巧可以說(shuō)非常有用,學(xué)會(huì)設(shè)置之后,再也不用擔(dān)心maven依賴下載變慢的問(wèn)題,需要的朋友可以參考下2021-05-05
關(guān)于SpringCloud的Bus消息總線圖文詳解
這篇文章主要介紹了關(guān)于SpringCloud的Bus消息總線圖文詳解,Spring Cloud Bus是用來(lái)將分布式系統(tǒng)的節(jié)點(diǎn)與輕量級(jí)消息系統(tǒng)鏈接起來(lái)的框架,它整合了Java的事件處理機(jī)制和消息中間件的功能,需要的朋友可以參考下2023-05-05
mybatis實(shí)現(xiàn)獲取入?yún)⑹荓ist和Map的取值
這篇文章主要介紹了mybatis實(shí)現(xiàn)獲取入?yún)⑹荓ist和Map的取值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
使用javassist動(dòng)態(tài)生成類的配置代碼
Javassist它是一個(gè)用 Java 編輯字節(jié)碼的類庫(kù),它使 Java 程序能夠在運(yùn)行時(shí)定義新類,并在 JVM 加載時(shí)修改類文件,本文給大家介紹使用javassist動(dòng)態(tài)生成類的實(shí)例代碼,感興趣的朋友一起看看吧2022-09-09
Java基于正則實(shí)現(xiàn)的日期校驗(yàn)功能示例
這篇文章主要介紹了Java基于正則實(shí)現(xiàn)的日期校驗(yàn)功能,涉及java文件讀取、日期轉(zhuǎn)換及字符串正則匹配相關(guān)操作技巧,需要的朋友可以參考下2017-03-03
Java游戲俄羅斯方塊的實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Java游戲俄羅斯方塊的實(shí)現(xiàn)實(shí)例的相關(guān)資料,這里實(shí)現(xiàn)簡(jiǎn)單的俄羅斯方塊幫助大家學(xué)習(xí)理解基礎(chǔ)知識(shí),需要的朋友可以參考下2017-08-08

