摘要:本人郵箱歡迎轉(zhuǎn)載轉(zhuǎn)載請(qǐng)注明網(wǎng)址代碼已經(jīng)全部托管有需要的同學(xué)自行下載類學(xué)習(xí)線程的開(kāi)發(fā)者首先遇到的第一個(gè)類就是通過(guò)使用類我們就可以啟動(dòng)停止中斷一個(gè)線程在同一個(gè)時(shí)間片里可能會(huì)有多個(gè)線程在執(zhí)行每個(gè)線程都擁有它自己的方法調(diào)用堆棧參數(shù)和變量每個(gè)至少會(huì)有
Thread類本人郵箱:
歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明網(wǎng)址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經(jīng)全部托管github有需要的同學(xué)自行下載
學(xué)習(xí)java線程的開(kāi)發(fā)者,首先遇到的第一個(gè)類就是Thread,通過(guò)使用Thread類,我們就可以啟動(dòng),停止,中斷一個(gè)線程. 在同一個(gè)時(shí)間片里, 可能會(huì)有多個(gè)線程在執(zhí)行, 每個(gè)線程都擁有它自己的方法調(diào)用堆棧, 參數(shù)和變量.每個(gè)app至少會(huì)有一個(gè)線程--主線程(main thread).
創(chuàng)建一個(gè)線程 java創(chuàng)建線程有兩種方式創(chuàng)建一個(gè)繼承Thread的子類,并實(shí)現(xiàn)run方法
使用Thread的構(gòu)造方法public Thread(Runnable target)創(chuàng)建,這個(gè)需要傳入一個(gè)實(shí)現(xiàn)Runnable接口的子類
實(shí)現(xiàn)下面我們分別以這兩種方式實(shí)現(xiàn)一下.
編寫SubThread繼承Thread,并覆蓋run方法 SubThread.java
public class SubThread extends Thread{ @Override public void run() { for (int i = 0; i < 10; i ++){ System.out.println(Thread.currentThread().getName() + ":" + i); } } public static void main(String[] args) { System.out.println("begin main"); SubThread sub = new SubThread(); sub.start(); System.out.println("end main"); } }
編寫SubRunnable實(shí)現(xiàn)Runnable,然后使用構(gòu)造器Thread(Runnable) 創(chuàng)建一個(gè)線程
public class SubRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 10; i ++){ System.out.println(Thread.currentThread().getName() + ":" + i); } } public static void main(String[] args) { System.out.println("begin main"); Thread thread = new Thread(new SubRunnable()); thread.start(); System.out.println("end main"); } }區(qū)別
使用第一種方法創(chuàng)建的話,你可以在run方法中,可以用this直接調(diào)用線程的方法,比如獲取線程的id-->this.getId()
而使用第二方法創(chuàng)建線程,在run中,this對(duì)象壓根就沒(méi)有getId()這個(gè)方法,這個(gè)時(shí)候你只能用Thread.cuurentThread()這個(gè)靜態(tài)方法獲取該線程.
在這里一般推薦使用第二種方法創(chuàng)建,因?yàn)檫@樣比較符合面對(duì)象的思路,Thread就只負(fù)責(zé)線程的啟動(dòng),停止,中斷等操作,而Runnable就只負(fù)責(zé)線程要運(yùn)行某一個(gè)具體任務(wù).
讓線程"睡"一會(huì)不管使用那種方式創(chuàng)建線程,都可以調(diào)用Thread.cuurentThread()獲取當(dāng)前的線程
還有,Thread其實(shí)也是Runnable的一個(gè)子類
除了上面兩種創(chuàng)建方法,其中還有另外一種方法創(chuàng)建線程,那就是實(shí)現(xiàn)ThreadFactory接口,這種比較適合批量生成某一種規(guī)格的線程
調(diào)用線程的Thread.sleep()方法會(huì)讓線程睡眠一段時(shí)間,這個(gè)時(shí)候線程會(huì)掛起,然后將CPU的時(shí)間片轉(zhuǎn)移給其他線程,讓其他線程獲得執(zhí)行的機(jī)會(huì).
停止線程Thread.sleep()接收一個(gè)毫秒值做完參數(shù),并拋出一個(gè)InterruptedException異常.
不管是使用哪一種方法創(chuàng)建線程,run方法的任務(wù)執(zhí)行完了,線程就自動(dòng)停止.
如果想在中途就停止線程,有下面幾種方式
調(diào)用線程的interrupt()方法,這時(shí)線程的中斷位會(huì)被標(biāo)識(shí),并拋出InterruptedException,例如:
public class StopThread1 { public static void main(String[] args) throws InterruptedException { System.out.println("begin main"); Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i ++){ try { Thread.sleep(100); System.out.println(Thread.currentThread().getName() + ":" + i); } catch (InterruptedException e) { break; } } } }); thread.start(); System.out.println("main sleep 500ms"); Thread.sleep(500); thread.interrupt(); System.out.println("end main"); } }
在調(diào)用thread.interrupt();這個(gè)語(yǔ)句時(shí),會(huì)對(duì)該線程的中斷狀態(tài)標(biāo)識(shí)為true,然后在拋出InterruptedException異常時(shí),會(huì)清空該中斷位.
修改程序,在拋出InterruptedException中添加System.out.println("InterruptedException:" + Thread.currentThread().isInterrupted());,然后再thread.interrupt();后面添加System.out.println("thread.isInterrupted:" + thread.isInterrupted());.然后運(yùn)行程序.這時(shí)候運(yùn)行結(jié)果有可能打印出thread.isInterrupted:true;InterruptedException:false或者打印出thread.isInterrupted:false;InterruptedException:false,運(yùn)行多次結(jié)果都有可能不一致,這個(gè)是因?yàn)橹骶€程和子線程都通知在執(zhí)行,還沒(méi)有來(lái)的及執(zhí)行主線程的打印語(yǔ)句,子線程異常中的打印語(yǔ)句就已經(jīng)執(zhí)行了.
可以在線程中加一個(gè)boolean成員變量,提供setter方法,然后在run方法中判斷該變量是否為true,若為true則停止線程,否則繼續(xù)
public class StopThread2 { public static class StopRunnable implements Runnable{ private boolean isStop = false; public void setStop(){ this.isStop = true; } @Override public void run() { int count = 0; while (!isStop){ try { Thread.sleep(100); System.out.println(Thread.currentThread().getName() + ":" + count++); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { System.out.println("begin main"); StopRunnable stop = new StopRunnable(); Thread thread = new Thread(stop); thread.start(); Thread.sleep(200); stop.setStop(); System.out.println("end main"); } }線程的屬性
id: 通過(guò)Thread.getId()可以獲取線程的id,線程的id是一個(gè)自增長(zhǎng)的long, 不能修改
name: 通過(guò)Thread.getName(), 用一個(gè)字符串來(lái)標(biāo)識(shí)線程的名字,可以通過(guò)Thread.setName()或部分構(gòu)造器修改線程的名字
priority: 線程的優(yōu)先級(jí),線程創(chuàng)建默認(rèn)優(yōu)先級(jí)為5, 最小為優(yōu)先級(jí)為1, 最大為10.優(yōu)先級(jí)大的線程有機(jī)會(huì)先執(zhí)行.但具體那個(gè)線程先執(zhí)行還是要看CPU的心情了.
state: 線程的狀態(tài), 線程的狀態(tài)有以下幾種
Thread.State.NEW: _新建狀態(tài)_:這個(gè)是線程已經(jīng)被創(chuàng)建但還沒(méi)有調(diào)用"start()"方法時(shí)的狀態(tài)
Thread.State.RUNNABLE: 運(yùn)行狀態(tài) 當(dāng)前線程已經(jīng)在JVM中執(zhí)行
Thread.State.BLOCKED: 阻塞狀態(tài) 表示當(dāng)前線程在等待進(jìn)入一個(gè)同步塊或同步方法,也可以等到一個(gè)同步快被提交. 常見(jiàn)的有IO阻塞等.
Thread.State.WAITING: 等待狀態(tài) 但線程調(diào)用Object.wait(),Thread.join(),LockSupport.park()就會(huì)進(jìn)入等待狀態(tài).當(dāng)前線程在等待其他線程執(zhí)行某一個(gè)特定操作.比如:當(dāng)前線程執(zhí)行Object.wait(),那么就需要其他線程執(zhí)行Object.notify()或Object.notifyAll(),如果線程執(zhí)行了Thread.join(),則需要等到指定的線程執(zhí)行結(jié)束.
Thread.State.TIMED_WAITING: 有時(shí)間的等待 線程在等待某一個(gè)等待的時(shí)間.比如,線程執(zhí)行了Thread.sleep,Object.wait(long),Thread.join(long)等
Thread.State.TERMINATED: 終結(jié) 線程已經(jīng)執(zhí)行完畢.
daemon: 這個(gè)用來(lái)標(biāo)識(shí)線程為守護(hù)線程或非守護(hù)線程的,默認(rèn)創(chuàng)建的線程都是非守護(hù)線程.應(yīng)用程序所有的非守護(hù)線程執(zhí)行完畢之后,則程序就停止運(yùn)行.比如主線程都是非守護(hù)線程,所以主線程會(huì)等到主線程的所有語(yǔ)句執(zhí)行完成,程序才會(huì)停止運(yùn)行.JVM的資源回收則是一個(gè)守護(hù)線程.
public class TestDaemonThread { public static void main(String[] args) { System.out.println("start main"); Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 10; i ++){ try { System.out.println(Thread.currentThread().getName() + ":" + i); Thread.sleep(10); } catch (Exception e) { e.printStackTrace(); } } } }); thread.start(); System.out.println("end main"); } }
Thread.join()該例子中,程序必須等到主線程和子線程同時(shí)執(zhí)行完成才會(huì)停止,因?yàn)槟J(rèn)創(chuàng)建的線程都是非守護(hù)線程,如果在thread.start();前加入thread.setDaemon(true);, 那么程序不會(huì)等子線程執(zhí)行完才結(jié)束程序的.
等到某線程執(zhí)行完畢才開(kāi)始執(zhí)行,如果調(diào)用Thread.join(long)則表示等到某線程執(zhí)行完畢或指定的超時(shí)時(shí)間結(jié)束后才開(kāi)始執(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(); } }
Thread.yield上面的例子,thread2線程會(huì)等thread1執(zhí)行完之后才開(kāi)始執(zhí)行
這個(gè)方法標(biāo)識(shí)當(dāng)前線程會(huì)按時(shí)線程調(diào)度者讓其他線程先執(zhí)行.但CPU是否讓其他線程優(yōu)先執(zhí)行,還是要看CPU的心情了.
線程的異常如果線程發(fā)現(xiàn)一些運(yùn)行時(shí)異常而沒(méi)有在run方法俘獲,會(huì)怎么辦?
程序會(huì)打印出一推錯(cuò)誤堆棧,如果我們先把線程的錯(cuò)誤按照某種可讀的方式打印到問(wèn)題,但又不想在每個(gè)run方法中增加try{...}catch(Exception e){...}怎么辦?
我們查看Thread類的源碼發(fā)現(xiàn),在Thread中有一個(gè)內(nèi)部接口UncaughtExceptionHandler,這個(gè)正是我們所需要的.實(shí)現(xiàn)這個(gè)接口,并調(diào)用Thread.setUncaughtExceptionHandler,那么但線程出現(xiàn)時(shí),則會(huì)回調(diào)uncaughtException方法
public class ThreadExceptionTest { public static void main(String[] args) throws InterruptedException { System.out.println("begin main"); Thread thread = new Thread(() -> { int i = 1 / 0; },"myThread"); thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(String.format("%s發(fā)生異常%s", t.getName(), e.getMessage())); } }); thread.start(); System.out.println("end main"); } }打賞
如果覺(jué)得我的文章寫的還過(guò)得去的話,有錢就捧個(gè)錢場(chǎng),沒(méi)錢給我捧個(gè)人場(chǎng)(幫我點(diǎn)贊或推薦一下)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67044.html
摘要:多線程同步工具箱之篇前言的多線程協(xié)調(diào)工具,,,都是在多線程代碼中使用比較多的工具類之一。毫不夸張的說(shuō),這幾個(gè)類,是等同于解決多線程問(wèn)的包,實(shí)在有必要添加到程序員的工具箱里面。 Java多線程同步工具箱之CountDownLatch篇 前言 Java的多線程協(xié)調(diào)工具CountDownLatch,Semaphore,CyclicBarrier,ReadWriteLock都是在多線程代碼中使...
摘要:多線程技術(shù)是個(gè)很龐大的課題,編程思想這本書英文版,以下簡(jiǎn)稱中也用了頁(yè)介紹的多線程體系。一個(gè)線程歸屬于唯一的進(jìn)程,線程無(wú)法脫離進(jìn)程而存在。五線程內(nèi)數(shù)據(jù)線程的私有數(shù)據(jù)僅歸屬于一個(gè)線程,不在線程之間共享,例如,,。 多線程技術(shù)是個(gè)很龐大的課題,《Java編程思想》這本書(英文版,以下簡(jiǎn)稱TIJ)中也用了136頁(yè)介紹Java的多線程體系。的確,Java語(yǔ)言發(fā)展到今天,多線程機(jī)制相比其他的語(yǔ)言從...
摘要:時(shí)間年月日星期六說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。慕課網(wǎng)教學(xué)源碼無(wú)學(xué)習(xí)源碼第一章課前準(zhǔn)備前言課程說(shuō)明比較和這兩種線程創(chuàng)建的方式,需要知道和的基本創(chuàng)建方式。一旦主線程獲取到了用戶的輸入,這時(shí)候,阻塞就會(huì)解除掉,主線程繼續(xù)運(yùn)行,直到結(jié)束。 時(shí)間:2017年07月08日星期六說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)源碼:無(wú)學(xué)習(xí)源碼:https://g...
摘要:本人郵箱歡迎轉(zhuǎn)載轉(zhuǎn)載請(qǐng)注明網(wǎng)址代碼已經(jīng)全部托管有需要的同學(xué)自行下載引言在之前的例子我們要?jiǎng)?chuàng)建多個(gè)線程處理一批任務(wù)的時(shí)候我是通過(guò)創(chuàng)建線程數(shù)組或者使用線程集合來(lái)管理的但是這樣做不太好因?yàn)檫@些線程沒(méi)有被重復(fù)利用所以這里要引入線程池今天我們就講線程 本人郵箱: 歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明網(wǎng)址 http://blog.csdn.net/tianshi_kcogithub: https://github...
摘要:目錄源碼之下無(wú)秘密做最好的源碼分析教程源碼分析之番外篇的前生今世的前生今世之一簡(jiǎn)介的前生今世之二小結(jié)的前生今世之三詳解的前生今世之四詳解源碼分析之零磨刀不誤砍柴工源碼分析環(huán)境搭建源碼分析之一揭開(kāi)神秘的紅蓋頭源碼分析之一揭開(kāi)神秘的紅蓋頭客戶端 目錄 源碼之下無(wú)秘密 ── 做最好的 Netty 源碼分析教程 Netty 源碼分析之 番外篇 Java NIO 的前生今世 Java NI...
閱讀 2582·2023-04-26 00:57
閱讀 946·2021-11-25 09:43
閱讀 2248·2021-11-11 16:55
閱讀 2292·2019-08-30 15:53
閱讀 3623·2019-08-30 15:52
閱讀 1496·2019-08-30 14:10
閱讀 3405·2019-08-30 13:22
閱讀 1238·2019-08-29 11:18