JAVA面試題 start()和run()詳解
問(wèn)題
面試官:請(qǐng)問(wèn)啟動(dòng)線程是start()還是run()方法,能談?wù)剢幔?/p>
應(yīng)聘者:start()方法
當(dāng)用start()開(kāi)始一個(gè)線程后,線程就進(jìn)入就緒狀態(tài),使線程所代表的虛擬處理機(jī)處于可運(yùn)行狀態(tài),這意味著它可以由JVM調(diào)度并執(zhí)行。但是這并不意味著線程就會(huì)立即運(yùn)行。只有當(dāng)cpu分配時(shí)間片時(shí),這個(gè)線程獲得時(shí)間片時(shí),才開(kāi)始執(zhí)行run()方法。start()是方法,它調(diào)用run()方法.而run()方法是你必須重寫(xiě)的. run()方法中包含的是線程的主體(真正的邏輯)。
繼承Thread類的啟動(dòng)方式
public class ThreadTest { public static void main(String[] args) { MyThread t =new MyThread(); t.start(); } } class MyThread extends Thread{ @Override public void run() { System.out.println("Hello World!"); } }
實(shí)現(xiàn)Runnable接口的啟動(dòng)方式
public class ThreadTest { public static void main(String[] args) { Thread t =new Thread(new MyRunnable()); t.start(); } } class MyRunnable implements Runnable{ @Override public void run() { System.out.println("Hello World!"); } }
實(shí)際上這兩種啟動(dòng)線程的方式原理是一樣的。首先都是調(diào)用本地方法啟動(dòng)一個(gè)線程,其次是在這個(gè)線程里執(zhí)行目標(biāo)對(duì)象的run()方法。那么這個(gè)目標(biāo)對(duì)象是什么呢?為了弄明白這個(gè)問(wèn)題,我們來(lái)看看Thread類的run()方法的實(shí)現(xiàn):
public void run() { if (target != null) { target.run(); } }
當(dāng)我們采用實(shí)現(xiàn)Runnable接口的方式來(lái)實(shí)現(xiàn)線程的情況下,在調(diào)用new Thread(Runnable target)構(gòu)造器時(shí),將實(shí)現(xiàn)Runnable接口的類的實(shí)例設(shè)置成了線程要執(zhí)行的主體所屬的目標(biāo)對(duì)象target,當(dāng)線程啟動(dòng)時(shí),這個(gè)實(shí)例的 run()方法就被執(zhí)行了。
當(dāng)我們采用繼承Thread的方式實(shí)現(xiàn)線程時(shí),線程的這個(gè)run()方法被重寫(xiě)了,所以當(dāng)線程啟動(dòng)時(shí),執(zhí)行的是這個(gè)對(duì)象自身的 run()方法。
總結(jié)起來(lái):如果我們采用的是繼承Thread類的方式,那么這個(gè)target就是線程對(duì)象自身,如果我們采用的是實(shí)現(xiàn)Runnable接口的方式,那么這個(gè)target就是實(shí)現(xiàn)了Runnable接口的類的實(shí)例。
我們?cè)賮?lái)看一道混跡于各大面試公司筆試的題目:
public class EqualsTest { public static void main(String args[]) { Thread t = new Thread() { public void run() { pong(); } }; t.run(); System.out.print("ping"); } static void pong() { System.out.print("pong"); } }
這里的標(biāo)準(zhǔn)答案是:pongping
這里直接調(diào)用線程的run方法,就相當(dāng)于調(diào)用普通方法一樣,由上往下執(zhí)行,所以最后的結(jié)果是pongping。但是如果上面改成t.start()之后,這個(gè)結(jié)果就不固定了,因?yàn)檫@里有兩個(gè)線程(其實(shí)還有一個(gè)守護(hù)線程,這里就先忽略),main線程和 t 線程,這兩個(gè)線程獲得cpu的時(shí)間就會(huì)不固定了,誰(shuí)先獲得CPU執(zhí)行權(quán),誰(shuí)就先打印結(jié)果,所以最后的結(jié)果可能pongping也可能是pingpong。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java判斷一個(gè)時(shí)間是否在當(dāng)前時(shí)間區(qū)間代碼示例
這篇文章主要給大家介紹了關(guān)于使用Java判斷一個(gè)時(shí)間是否在當(dāng)前時(shí)間區(qū)間的相關(guān)資料,在日常開(kāi)發(fā)中我們經(jīng)常會(huì)涉及到時(shí)間的大小比較或者是判斷某個(gè)時(shí)間是否在某個(gè)時(shí)間段內(nèi),需要的朋友可以參考下2023-07-07詳解在springmvc中解決FastJson循環(huán)引用的問(wèn)題
本篇文章主要介紹了在springmvc中解決FastJson循環(huán)引用的問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01spring Boot與Mybatis整合優(yōu)化詳解
關(guān)于spring-boot與mybatis整合優(yōu)化方面的介紹,就是Mybatis-Spring-boot-starter的介紹,具體內(nèi)容詳情大家參考下本文2017-07-07Mybatis控制臺(tái)打印Sql語(yǔ)句的實(shí)現(xiàn)代碼
MyBatis是一個(gè)支持普通SQL查詢,存儲(chǔ)過(guò)程和高級(jí)映射的優(yōu)秀持久層框架,下面給大家介紹Mybatis控制臺(tái)打印Sql語(yǔ)句的實(shí)現(xiàn)代碼,非常不錯(cuò),感興趣的朋友一起看下吧2016-07-07Java中出現(xiàn)java.lang.IllegalStateException異常錯(cuò)誤的解決
這篇文章主要介紹了Java中出現(xiàn)java.lang.IllegalStateException異常錯(cuò)誤的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01SpringBoot 項(xiàng)目添加 MDC 日志鏈路追蹤的執(zhí)行流程
日志鏈路追蹤就是將一個(gè)標(biāo)志跨線程進(jìn)行傳遞,在一般的小項(xiàng)目中也就是在你新起一個(gè)線程的時(shí)候,或者使用線程池執(zhí)行任務(wù)的時(shí)候會(huì)用到,比如追蹤一個(gè)用戶請(qǐng)求的完整執(zhí)行流程,本文給大家介紹SpringBoot MDC 日志鏈路追蹤的代碼,感興趣的朋友一起看看吧2021-06-06