(一)java多线程之Thread
目錄
- Thread類
- 創(chuàng)建一個線程
- java創(chuàng)建線程有兩種方式
- 實現(xiàn)
- 區(qū)別
- 讓線程"睡"一會
- 停止線程
- 線程的屬性
- Thread.join()
- Thread.yield
- 線程的異常
- 打賞
本人郵箱: kco1989@qq.com
歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明網(wǎng)址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經(jīng)全部托管github有需要的同學(xué)自行下載
Thread類
學(xué)習(xí)java線程的開發(fā)者,首先遇到的第一個類就是Thread,通過使用Thread類,我們就可以啟動,停止,中斷一個線程. 在同一個時間片里, 可能會有多個線程在執(zhí)行, 每個線程都擁有它自己的方法調(diào)用堆棧, 參數(shù)和變量.每個app至少會有一個線程--主線程(main thread).
創(chuàng)建一個線程
java創(chuàng)建線程有兩種方式
實現(xiàn)
下面我們分別以這兩種方式實現(xiàn)一下.
- 編寫SubThread繼承Thread,并覆蓋run方法 SubThread.java
- 編寫SubRunnable實現(xiàn)Runnable,然后使用構(gòu)造器Thread(Runnable) 創(chuàng)建一個線程
區(qū)別
- 使用第一種方法創(chuàng)建的話,你可以在run方法中,可以用this直接調(diào)用線程的方法,比如獲取線程的id-->this.getId()
- 而使用第二方法創(chuàng)建線程,在run中,this對象壓根就沒有g(shù)etId()這個方法,這個時候你只能用Thread.cuurentThread()這個靜態(tài)方法獲取該線程.
- 在這里一般推薦使用第二種方法創(chuàng)建,因為這樣比較符合面對象的思路,Thread就只負責線程的啟動,停止,中斷等操作,而Runnable就只負責線程要運行某一個具體任務(wù).
不管使用那種方式創(chuàng)建線程,都可以調(diào)用Thread.cuurentThread()獲取當前的線程
還有,Thread其實也是Runnable的一個子類
除了上面兩種創(chuàng)建方法,其中還有另外一種方法創(chuàng)建線程,那就是實現(xiàn)ThreadFactory接口,這種比較適合批量生成某一種規(guī)格的線程
讓線程"睡"一會
調(diào)用線程的Thread.sleep()方法會讓線程睡眠一段時間,這個時候線程會掛起,然后將CPU的時間片轉(zhuǎn)移給其他線程,讓其他線程獲得執(zhí)行的機會.
Thread.sleep()接收一個毫秒值做完參數(shù),并拋出一個InterruptedException異常.
停止線程
不管是使用哪一種方法創(chuàng)建線程,run方法的任務(wù)執(zhí)行完了,線程就自動停止.
如果想在中途就停止線程,有下面幾種方式
- 調(diào)用線程的interrupt()方法,這時線程的中斷位會被標識,并拋出InterruptedException,例如:
在調(diào)用thread.interrupt();這個語句時,會對該線程的中斷狀態(tài)標識為true,然后在拋出InterruptedException異常時,會清空該中斷位.
修改程序,在拋出InterruptedException中添加System.out.println("InterruptedException:" + Thread.currentThread().isInterrupted());,然后再thread.interrupt();后面添加System.out.println("thread.isInterrupted:" + thread.isInterrupted());.然后運行程序.
這時候運行結(jié)果有可能打印出thread.isInterrupted:true;InterruptedException:false或者打印出thread.isInterrupted:false;InterruptedException:false,運行多次結(jié)果都有可能不一致,這個是因為主線程和子線程都通知在執(zhí)行,還沒有來的及執(zhí)行主線程的打印語句,子線程異常中的打印語句就已經(jīng)執(zhí)行了.
- 可以在線程中加一個boolean成員變量,提供setter方法,然后在run方法中判斷該變量是否為true,若為true則停止線程,否則繼續(xù)
線程的屬性
- id: 通過Thread.getId()可以獲取線程的id,線程的id是一個自增長的long, 不能修改
- name: 通過Thread.getName(), 用一個字符串來標識線程的名字,可以通過Thread.setName()或部分構(gòu)造器修改線程的名字
- priority: 線程的優(yōu)先級,線程創(chuàng)建默認優(yōu)先級為5, 最小為優(yōu)先級為1, 最大為10.優(yōu)先級大的線程有機會先執(zhí)行.但具體那個線程先執(zhí)行還是要看CPU的心情了.
- state: 線程的狀態(tài), 線程的狀態(tài)有以下幾種
- Thread.State.NEW: 新建狀態(tài):這個是線程已經(jīng)被創(chuàng)建但還沒有調(diào)用'start()'方法時的狀態(tài)
- Thread.State.RUNNABLE: 運行狀態(tài) 當前線程已經(jīng)在JVM中執(zhí)行
- Thread.State.BLOCKED: _阻塞狀態(tài)_ 表示當前線程在等待進入一個同步塊或同步方法,也可以等到一個同步快被提交. 常見的有IO阻塞等.
- Thread.State.WAITING: _等待狀態(tài)_ 但線程調(diào)用Object.wait(),Thread.join(),LockSupport.park()就會進入等待狀態(tài).當前線程在等待其他線程執(zhí)行某一個特定操作.比如:當前線程執(zhí)行Object.wait(),那么就需要其他線程執(zhí)行Object.notify()或Object.notifyAll(),如果線程執(zhí)行了Thread.join(),則需要等到指定的線程執(zhí)行結(jié)束.
- Thread.State.TIMED_WAITING: 有時間的等待 線程在等待某一個等待的時間.比如,線程執(zhí)行了Thread.sleep,Object.wait(long),Thread.join(long)等
- Thread.State.TERMINATED: 終結(jié) 線程已經(jīng)執(zhí)行完畢.
- daemon: 這個用來標識線程為守護線程或非守護線程的,默認創(chuàng)建的線程都是非守護線程.應(yīng)用程序所有的非守護線程執(zhí)行完畢之后,則程序就停止運行.比如主線程都是非守護線程,所以主線程會等到主線程的所有語句執(zhí)行完成,程序才會停止運行.JVM的資源回收則是一個守護線程.
該例子中,程序必須等到主線程和子線程同時執(zhí)行完成才會停止,因為默認創(chuàng)建的線程都是非守護線程,如果在thread.start();前加入thread.setDaemon(true);, 那么程序不會等子線程執(zhí)行完才結(jié)束程序的.
Thread.join()
等到某線程執(zhí)行完畢才開始執(zhí)行,如果調(diào)用Thread.join(long)則表示等到某線程執(zhí)行完畢或指定的超時時間結(jié)束后才開始執(zhí)行
public class ThreadJoinTest {public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {for (int i = 0;i < 10; i ++){try {Thread.sleep(10);System.out.println(Thread.currentThread().getName() + ":" + i);} catch (InterruptedException e) {e.printStackTrace();}}}, "thread1");Thread thread2 = new Thread(() -> {try {thread1.join();for (int i = 0;i < 10; i ++){Thread.sleep(10);System.out.println(Thread.currentThread().getName() + ":" + i);}} catch (InterruptedException e) {e.printStackTrace();}}, "thread2");thread1.start();thread2.start();} }上面的例子,thread2線程會等thread1執(zhí)行完之后才開始執(zhí)行
Thread.yield
這個方法標識當前線程會按時線程調(diào)度者讓其他線程先執(zhí)行.但CPU是否讓其他線程優(yōu)先執(zhí)行,還是要看CPU的心情了.
線程的異常
如果線程發(fā)現(xiàn)一些運行時異常而沒有在run方法俘獲,會怎么辦?
程序會打印出一推錯誤堆棧,如果我們先把線程的錯誤按照某種可讀的方式打印到問題,但又不想在每個run方法中增加try{...}catch(Exception e){...}怎么辦?
我們查看Thread類的源碼發(fā)現(xiàn),在Thread中有一個內(nèi)部接口UncaughtExceptionHandler,這個正是我們所需要的.實現(xiàn)這個接口,并調(diào)用Thread.setUncaughtExceptionHandler,那么但線程出現(xiàn)時,則會回調(diào)uncaughtException方法
打賞
如果覺得我的文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧個人場(幫我點贊或推薦一下)
轉(zhuǎn)載于:https://www.cnblogs.com/kco1989/p/6760763.html
總結(jié)
以上是生活随笔為你收集整理的(一)java多线程之Thread的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《How Tomcat Works》读书
- 下一篇: ubuntu 16.0.4 配置 ten