新手編程:Java多線程中Thread與Runnable的區別

2020-12-12 酷愛小島

Java多線程中Thread與Runnable的區別

定義

extends Thread

子類繼承Thread具備多線程能力,可以實現多線程;啟動線程的方法:①創建子類對象 ②對象名.start();不建議使用:避免多線程OOP單繼承的局限性(OOP:Object Oriented Programming,面向對象的編程、類似的還有OOD(面向對象的設計),OOA(面向對象的分析));implements Runnable

實現Runnable接口具有多線程能力,可以實現多線程啟動線程的方法:①創建子類對象 ②new Thread(對象).strart();推薦使用:避免OOP單繼承的局限性,方便被同一個對象多次使用;實際上所有的多線程代碼都是通過執行Thread的start()方法來運行的。所以不管是繼承Thread類還是實現Runnable接口來實現多線程,最終都是通過Thread對象的API來控制線程的,因此熟悉Thread類的API是進行多線程編程的基礎。(點擊查看什麼是API

示例

繼承Thread實現多線程1

package 多線程1;

public class TestThread1 extends Thread {

@Override

public void run() {

for (int i = 0; i < 20; i++) {

System.out.println("子線程正在執行..."+i);

}

}

public static void main(String[] args) {

TestThread1 testThread1 = new TestThread1();

testThread1.start();

for (int i = 0; i < 500; i++) {

System.out.println("主線程正在執行..."+i);

}

}

}

上述示例執行後可以看到:主線程和子線程的執行順序本該是「先執行子線程、再執行主線程」,事實上卻是主線程和子線程交替執行(無法人為控制,由CPU調度執行),這便是多線程的特徵;

繼承Thread實現多線程2——下載網絡圖片

package 多線程1;

import org.apache.commons.io.FileUtils;

import java.io.File;

import java.io.IOException;

import java.net.MalformedURLException;

import java.net.URL;

//練習網絡下載圖片

public class TestThread2 extends Thread {

private String url;

private String name;

public TestThread2(String url,String name){

this.name=name;

this.url=url;

}

@Override

public void run() {

WebDownloader webDownloader = new WebDownloader();

webDownloader.Downloader(url,name);

System.out.println("下載的文件名為 "+name);

}

public static void main(String[] args) {

TestThread2 t1 = new TestThread2("雙引號內填網絡圖片url","p1.jpg");

TestThread2 t2 = new TestThread2("雙引號內填網絡圖片url","p2.jpg");

TestThread2 t3 = new TestThread2("雙引號內填網絡圖片url","p3.jpg");

t1.start();

t2.start();

t3.start();

}

}

//下載器

class WebDownloader{

public void Downloader(String url,String name) {

try {

FileUtils.copyURLToFile(new URL(url),new File(name));

} catch (IOException e) {

e.printStackTrace();

System.out.println("IO錯誤!");

}

}

}

註:代碼中圖片為網絡上隨機尋找

由以上代碼也可以看出:下載的三張圖片的順序本應該是"p1-->p2-->p3",事實上執行後發現三張圖片的下載順序是隨機的(受CPU自由調度)。

Runnable接口實現多線程1

package 多線程1;

public class TestThread4_Runnable implements Runnable {

@Override

public void run() {

for (int i = 0; i < 10; i++) {

System.out.println("我是小兔子"+i);

}

}

public static void main(String[] args) {

TestThread4_Runnable testThread4_runnable = new TestThread4_Runnable();

Thread thread = new Thread(testThread4_runnable);

thread.start();

for (int i = 0; i < 800; i++) {

System.out.println("但我是一隻小腦斧哦~"+i);

}

}

}

上述代碼的執行結果也是隨機的,無法根據代碼的編寫順序來判斷執行順序。

Runnable接口實現多線程2——龜兔賽跑

package 多線程1;

public class Race implements Runnable {

private String winner=null;

@Override

public void run() {

for (int i = 0; i <= 100; i++) {

if(Thread.currentThread().getName().equals("兔子") && i%5==0) { //模擬兔子休息(1ms)

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

boolean winner = Win(i);

if(winner)

break;

System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");

}

}

public boolean Win(int steps){ //判斷比賽是否結束

if(winner!=null)

return true;

else if(steps==100) {

winner = Thread.currentThread().getName();

System.out.println(winner + "已經完成比賽!");

return true;

}

else

return false;

}

public static void main(String[] args) {

Race race = new Race();

new Thread(race,"兔子").start();

new Thread(race,"烏龜").start();

}

}

上述代碼模擬了龜兔賽跑,烏龜和兔子「隨機跑步」,兔子在中途「頻繁」休息,執行結果最終是烏龜成為了winner!

Thread.sleep()方法調用的目的是不讓當前線程獨自霸佔CPU,以留出一定時間給其他線程執行的機會。 實際上所有的多線程代碼執行順序都是不確定的,每次執行的結果都是隨機的。

但由於CPU的執行速度非常快,在測試的數量比較少的情況下可能無法看出隨機執行的現象!

相關焦點

  • 圖文並茂|創建線程和線程的常用方法(一次性講清線程基礎知識)
    一:為什麼要學多線程應付面試 :多線程幾乎是面試中必問的題,所以掌握一定的基礎知識是必須的。了解並發編程:實際工作中很少寫多線程的代碼,這部分代碼一般都被人封裝起來了,在業務中使用多線程的機會也不是很多(看具體項目),雖然代碼中很少會自己去創建線程,但是實際環境中每行代碼卻都是並行執行的,同一時刻大量請求同一個接口,並發可能會產生一些問題,所以也需要掌握一定的並發知識二:進程與線程1.
  • 手寫Java線程池(超詳細解說)
    ;5.線程池原型中具有2個隊列, 第一個是剛才上面提的RunnQueue(負責執行的任務), 第二個是ThreadQueue(負責存儲創建的每一個線程, 使用ArrayQueue實現, 這樣很好地維護管理了線程, 做到資源重用)6.removeThread方法: 刪除多餘的線程, 當用戶提交的任務數量小於線程池中創建的線程數量, 那麼就刪除一定數量的線程, 這樣才不會浪費線程資源.7.在構造方法中設置基本屬性
  • Java Thread類簡述
    今天我們來看下java.lang.Thread這個類。一般來說,線程包括以下這幾個狀態:創建(new)、就緒(runnable)、運行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)。 當需要新起一個線程來執行某個子任務時,就創建了一個線程。
  • Java之Thread和Runnable接口的區別
    各位小夥伴們大家好,好久不見,在之前的文章中,小編介紹了創建線程的兩種方式Java之創建多線程的第一種方式,thread類。這次小編要講的是這兩種方式的區別。其實就是實現Runnable接口創建多線程的好處,具體如下:避免了單繼承的局限性,一個類只能繼承一個類,這個類繼承了Thread類就不能繼承其它類。但是,實現了Runnable接口,還可以繼承其它的類,實現其它接口。
  • 實現多線程的標準操作,基於Runnable接口實現java多線程
    1 為什麼要用Runnable上一篇文章介紹了通過繼承Thread類,實現java多線程。但如果當我們創建的這個線程類還想繼承其他類的時候,這種方法就略顯局限了。這也是java單繼承的局限性。為了避免這種局限性,所以又提供了第二種多線程主體定義的形式:實現Runnable接口。2 創建一個實現Runnable的對象我們先創建一個RunnableDemo類,並在裡面創建一個MyThread2內部類,MyThread2實現Runnable接口。
  • 複習一波,Java多線程輕鬆搞定面試官
    使用匿名內部類創建線程註:實現Runnable和繼承Thread區別使用實現Runnable接口的方式更能體現面向對象的編程思想Runnable內部的代碼可以被多個線程共享,適用於多個線程處理同一資源的情況
  • Java之Runnable表達式的簡單介紹
    各位小夥伴們大家好,這次小編要介紹的是Runnable表達式當我們要啟動一個線程去完成任務的時候,通常的做法會通過java.lang.Runnable接口來定義任務內容,並使用java.lang.Thread類來啟動線程,代碼如下:/*創建Runnable接口的實現類,重寫
  • java入門避坑必讀,通過Thread類創建java多線程
    欲善編程,多看、敲、討論;動眼、手、大腦。1 為什麼要用多線程平常我們做crud的時候,用到多線程的機會不多。但當我們要處理一些複雜的業務時,或者提高程序處理效率時,就繞不開多線程的使用。也有些時候,我們需要對某個接口進行並發測試,也可以通過多線程來做一個性能測試小程序。2 創建一個java線程類我們先創建一個ThreadDemo類,並在裡面創建一個MyThread內部類,MyThread繼承Thread類。繼承之後,MyThread就是一個線程類了,具備了線程類的所有屬性。
  • 「原創」Java並發編程系列13|LookSupport
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫本文為何適原創並發編程系列第 13 篇,文末有本系列文章匯總。java.util.concurrent 中源碼頻繁使用的 LockSupport 來阻塞線程和喚醒線程,如 AQS 的底層實現用到 LockSupport.park()方法和 LockSupport.unpark()方法。LockSupport 到底是什麼?
  • Java線程篇-線程的狀態和分類概述
    Java開發中線程是經常用到的技術,那麼讓我們來回顧一下一些線程中經常考慮的問題吧1、線程分為用戶線程和守護線程,有什麼區別2、線程有哪些運行狀態一、什麼是線程線程,不過一般將就緒和運行都算作運行中新建:新建的線程對象,還未調用start方法就緒:已經具備了運行條件,等待CPU服務,這個狀態下,線程在就緒隊列中等待運行:線程具備運行條件,並獲得了CPU資源
  • 三萬字總結最全Java線程池源碼面試題
    1 為什麼要用線程池1.1 線程the more, the better?1、線程在java中是一個對象,更是作業系統的資源,線程創建、銷毀都需要時間。如果創建時間+銷毀時間>執行任務時間就很不合算。
  • 「原創」Java並發編程系列33|深入理解線程池(上)
    本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫並發編程必不可少的線程池,接下來分兩篇文章介紹線程池,本文是第一篇。介紹1.1 使用場景並發編程可以高效利用CPU資源,提升任務執行效率,但是多線程及線程間的切換也伴隨著資源的消耗。當遇到單個任務處理時間比較短,但需要處理的任務數量很大時,線程會頻繁的創建銷毀,大量的時間和資源都會浪費在線程的創建和銷毀上,效率很低。
  • JNI-Thread中start方法調用與run方法回調分析
    前言在java編程中,線程Thread是我們經常使用的類。那麼創建一個Thread的本質究竟是什麼,本文就此問題作一個探索。眾所周知java是一個跨平臺的語言,用java編譯的代碼可以運行在任何安裝了jvm的系統上。然而各個系統的底層實現肯定是有區別的,為了使java可以跨平臺,於是jvm提供了叫java native interface(JNI)的機制。
  • Java之Thread類的常用方法之獲取線程名稱
    Java之多線程原理的內存圖解。獲取當前線程的名稱有兩種方法1.使用Thread類中的方法getName(),String getName()返回該線程的名稱。2.可以獲取當前正在執行的線程,使用線程中的方法getName()獲取線程的名稱。static Thread current Thread()返回對當前正在執行的線程對象的引用。
  • Java 實現線程的方式有幾種方式?帶有返回值的線程怎麼實現?
    Java 實現線程的方式有幾種方式?帶有返回值的線程怎麼實現?在Java線程開發中,有幾種方法開啟線程?假如需要得到線程返回的信息怎麼辦?可以實現嗎?凱哥將通過源碼和大家一起分享下線程怎麼將返回值帶回來的。
  • 「011期」JavaSE面試題(十一):多線程(1)
    ,主要總結了Java中的多線程問題,多線程分為三篇來講,這篇是第一篇,在後續,會沿著第一篇開篇的知識線路一直總結下去,做到日更!Q:線程和進程的區別?特點:線程的劃分尺度小於進程,這使多線程程序擁有高並發性,進程在運行時各自內存單元相互獨立,線程之間內存共享,這使多線程編程可以擁有更好的性能和用戶體驗
  • 阿里巴巴資深Java專家10年經驗總結技術精華:多線程編程核心技術
    很多人學習完JavaSE/JavaEE之後想往更深入的技術進行探索,比如對大數據、分布式,高井發類的專題進行攻克時,立即遇到針對java lang包括線程類的學習,但線程類的學習並不像JDBC一樣簡單,學習曲線陡峭,多彎路與「坑」.要學習這些熱點技術, Java多線程技術避無可避。而本書將引領讀者拿下該「技術高地」.
  • java線程面試題集錦(第一版本)
    一、線程基礎1、什麼是線程?什麼是進程?他們之間有什麼區別?線程的好處和壞處?(壞處從單核CPU上下文切換帶來系統損耗來解答)2、Java中實現線程有那幾種方式?區別是什麼?(三種或者四種,根據繼承和接口特點區別)3、Thread類中的start和run方法的區別?(start方法內部含有native的start0,官方文檔解釋start0內部調用了run方法)4、守護線程和非守護線程的區別?
  • Python並發編程很簡單,一文搞清如何使用構造器創建線程
    上次已經和大家探討了關於進程和線程的區別和聯繫相關的東東,今天呢,咱們再次回到Python哦,和大家一起聊聊如何進行Python並發編程哦,大家也可以理解為如何在Python中進行多線程編程哦!好啦,廢話少說,咱們就開始吧!