摘要:線程啟動后系統(tǒng)就自動調(diào)用方法。守護(hù)線程的使用必須在之前設(shè)置,否則會跑出一個(gè)異常。你不能把正在運(yùn)行的常規(guī)線程設(shè)置為守護(hù)線程。在線程中產(chǎn)生的新線程也是的。線程的同步控制使用方法可以釋放對象鎖,使用或可以讓等待的一個(gè)或所有線程進(jìn)入就緒狀態(tài)。
線程的創(chuàng)建 線程:程序中單個(gè)順序的流控制稱為線程
一個(gè)進(jìn)程中可以含有多個(gè)線程
在操作系統(tǒng)中可以查看線程數(shù)
如:在Windows中,在任務(wù)管理器,右鍵,選擇列,選中“線程數(shù)”
一個(gè)進(jìn)程中的多個(gè)線程分享CPU(并發(fā)的或以時(shí)間片的方式)
圖示如下:
共享內(nèi)存(如多個(gè)線程訪問同一對象)
Java從語言級別支持多線程
如:
Object中wait(), notify(),java.lang中的類 Thread
線程啟動后,系統(tǒng)就自動調(diào)用run()方法。參考相關(guān)書:
所以我們自己調(diào)用run是不會產(chǎn)生新的線程的。
通常,run()方法執(zhí)行一個(gè)時(shí)間較長的操作
如一個(gè)循環(huán)
顯示一系列圖片
下載一個(gè)文件
創(chuàng)建線程 1. 通過繼承Thread類創(chuàng)建線程可以實(shí)現(xiàn)新線程:class MyThread extends Thread { public void run() { for(int i=0;i<100;i++) { System.out.print (" " + i); public void run() { ...} } //生成新線程 Thread thread = new Thread(mytask); thread.start(); } }
然而,并不推薦上述方式。參閱了《Introduction to Java Programming》:
This approach is, however, not recommended because it mixes the task and the mechanism of running the task. Separating the task from the thread is a preferred design.
因?yàn)門hread中還有其他的方法,這樣可能會混淆了Thread中固有的機(jī)制。
Thread類的方法很多,如下:
所以,更好的方式是重新定義一個(gè)類來實(shí)現(xiàn)抽象類Runnable類,然后采用基于接口的對象注入的方式新建一個(gè)Thread的對象。如第二個(gè)方法。
2. 通過向Thread()構(gòu)造方法傳遞Runnable對象來創(chuàng)建線程class MyTask implements Runnable { public void run() { ...} } //生成新線程 Thread thread = new Thread(mytask); thread.start(); }
圖示如下:
使用示例:
public class TestThread4Anonymous { public static void main(String args[]) { //匿名類 new Thread(){ public void run() { for(int i=0; i<10; i++) System.out.println(i); } }.start(); //Lambda表達(dá)式 new Thread( ( ) -> { for(int i=0; i<10; i++) System.out.println(" "+ i); } ).start(); } }線程的控制 對線程的基本控制
線程的啟動:thread.start()
線程的結(jié)束:常用的方法是設(shè)定一個(gè)標(biāo)記變量,結(jié)束相應(yīng)的循環(huán)及方法。
暫時(shí)阻止線程的執(zhí)行,比如在線程中用暫停方法:thread.sleep( 1000 );
線程的優(yōu)先級調(diào)用設(shè)定線程的優(yōu)先級setPriority( int priority)方法,默認(rèn)有以下三種
MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY
線程有兩種:
一類是普通線程(非Daemon線程)
在Java程序中,若還有非Demon線程,則整個(gè)程序就不會結(jié)束
一類是Daemon線程(守護(hù)線程,后臺線程)
使用setDaemon(true);如果普通線程結(jié)束了,則后臺線程自動終止。
注:垃圾回收線程是后臺線程
代碼public class daemon { public static void main(String args[]) { //創(chuàng)建子線程 Runnable t = new MyThread2(); Thread thread = new Thread(t); thread.setDaemon(true); thread.start(); System.out.println( "主線程開始運(yùn)行." ); try{ Thread.sleep(500); } catch(InterruptedException ex){} System.out.println("主線程結(jié)束,子線程由于設(shè)置為守護(hù)線程,所以也應(yīng)該提前結(jié)束."); } } class MyThread2 implements Runnable { public void run() { for(int i=0; i<10; i++ ){ System.out.println( "子線程應(yīng)該循環(huán)10次,當(dāng)前的第"+i+"次"); try{ Thread.sleep(100); } catch(InterruptedException ex){} } } }
輸出結(jié)果:
主線程開始運(yùn)行. 子線程應(yīng)該循環(huán)10次,當(dāng)前的第0次 子線程應(yīng)該循環(huán)10次,當(dāng)前的第1次 子線程應(yīng)該循環(huán)10次,當(dāng)前的第2次 子線程應(yīng)該循環(huán)10次,當(dāng)前的第3次 子線程應(yīng)該循環(huán)10次,當(dāng)前的第4次 主線程結(jié)束,子線程由于設(shè)置為守護(hù)線程,所以也應(yīng)該提前結(jié)束.
可以從上面看出,守護(hù)線程即使在運(yùn)行中,也應(yīng)該隨著主線程的結(jié)束而提前結(jié)束。
守護(hù)線程的使用:thread.setDaemon(true)必須在thread.start()之前設(shè)置,否則會跑出一個(gè)IllegalThreadStateException異常。你不能把正在運(yùn)行的常規(guī)線程設(shè)置為守護(hù)線程。
在Daemon線程中產(chǎn)生的新線程也是Daemon的。
守護(hù)線程應(yīng)該永遠(yuǎn)不去訪問固有資源,如文件、數(shù)據(jù)庫,因?yàn)樗鼤谌魏螘r(shí)候甚至在一個(gè)操作的中間發(fā)生中斷。
線程的同步為什么線程需要同步:
同時(shí)運(yùn)行的線程需要共享數(shù)據(jù)、就必須考慮其它線程的狀態(tài)與行為,這時(shí)就需要實(shí)現(xiàn)同步。
Java引入了對象互斥鎖的概念,來保證共享數(shù)據(jù)操作的完整性。
每個(gè)對象都對應(yīng)于一個(gè)monitor(監(jiān)視器),它上面 一個(gè)稱為“互斥鎖(lock, mutex)”的標(biāo)記,這個(gè)標(biāo)記用來保證在任一時(shí)刻,只能有一個(gè)線程訪問該對象。
關(guān)鍵字synchronized用來與對象的互斥鎖聯(lián)系。
synchronized的用法(2種)
對代碼片斷:
synchronized(對象){ 。。。。}
對某個(gè)方法:
synchronized放在方法聲明中,如
public synchronized void push(char c ){ 。。。。}
以上相當(dāng)于對synchronized(this), 表示整個(gè)方法為同步方法。
線程的同步控制使用wait()方法可以釋放對象鎖,使用notify()或notifyAll()可以讓等待的一個(gè)或所有線程進(jìn)入就緒狀態(tài)。
Java里面可以將wait()和notify()放在synchronized里面,是因?yàn)镴ava是這樣處理的:
在synchronized代碼被執(zhí)行期間,線程調(diào)用對象的wait()方法,會釋放對象鎖標(biāo)志,然后進(jìn)入等待狀態(tài),然后由其它線程調(diào)用notify()或者notifyAll()方法通知正在等待的線程。
并發(fā)的類JDK1.5中增加了更多的類,以便更靈活地使用鎖機(jī)制
Lock接口、ReentrantLock類,如下:
ReadWriteLock接口、ReentrantReadWriteLock類
如.writeLock(),.lock(), .readLock(),.unlock(),這些方法。
java.util.concurrent包中增加了一些方便的類
常用于很少寫入而讀取頻繁的對象
CopyOnWriteArrayList、 CopyOnWriteArraySet
ConcurrentHashMap
putIfAbsent(), remove(), replace()
ArrayBlockingQueue
使用線程池 線程池相關(guān)的類ExecutorService 接口、ThreadPoolExecutor 類
Executors 工具類
他們同樣位于Concurrent接口的實(shí)現(xiàn)下面,如下:
ExecutorService pool = Executors.newCachedThreadPool();
使用其execute( Runnable r)方法
代碼import java.util.concurrent.*; /** 創(chuàng)建線程池示例 */ public class ExecutorDemo { public static void main(String[] args) { // 創(chuàng)建線程池對象 ExecutorService executor = Executors.newCachedThreadPool(); // 提交任務(wù)到線程池 executor.execute(new PrintChar("a", 4)); executor.execute(new PrintChar("b", 2)); executor.execute(new PrintNum(2)); //關(guān)閉線程池 executor.shutdown(); } } class PrintChar implements Runnable { private char charToPrint; // The character to print private int times; // The times to repeat /** 給定打印次數(shù),打印特定字符 */ public PrintChar(char c, int t) { charToPrint = c; times = t; }
輸出結(jié)果
aaaabb 1 2流式操作及并行流
這里是指Java8新增的函數(shù)式思想,并不是具體的文件輸入輸出流。使得某些編程語句更加流暢的表達(dá)。
比如,對數(shù)組進(jìn)行流化:
Arrays.stream(a) .filter( i -> i>20 ) .map(i->i*i) .sorted() .distinct() .limit(10) .max();stream的操作種類
流操作分成兩類:
中間的 -中間的操作保持流打開狀態(tài),并允許后續(xù)的操作。
如: filter sorted limit map
末端的 - 末端的操作必須是對流的最終操作。
如: max min count forEach findAny
流步驟從某個(gè)源頭獲得一個(gè)流。
執(zhí)行一個(gè)或更多的中間的操作。
執(zhí)行一個(gè)末端的操作。
如何得到流對于數(shù)組
Arrays.stream(ary)
對于collection (包括List)
用 list.stream()
對于Map,沒有流,但提供了類似的方法
如map.putIfAbsent
map.computeIfPresent
map.merge
代碼import java.util.*; class UseStream { public static void main(String[] args) { Lista = Arrays.asList(1,2,5,7,3); System.out.println( a.stream() .mapToInt(i->(int)i) .filter( i -> i>2 ) .map( i -> i*i ) .sorted() .distinct() .limit(10) .max() ); } }
運(yùn)行結(jié)果:
OptionalInt[49]流的并行計(jì)算(略)
只需將上面代碼的.stream()換成 .parallelStream()。
其他都不變,就可以實(shí)現(xiàn)并行計(jì)算
可以說,stream就是為并行運(yùn)算而生的,它封裝的并行計(jì)算的大量內(nèi)部細(xì)節(jié)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65946.html
摘要:在這個(gè)范圍廣大的并發(fā)技術(shù)領(lǐng)域當(dāng)中多線程編程可以說是基礎(chǔ)和核心,大多數(shù)抽象并發(fā)問題的構(gòu)思與解決都是基于多線程模型來進(jìn)行的。一般來說,多線程程序會面臨三類問題正確性問題效率問題死鎖問題。 多線程編程或者說范圍更大的并發(fā)編程是一種非常復(fù)雜且容易出錯(cuò)的編程方式,但是我們?yōu)槭裁催€要冒著風(fēng)險(xiǎn)艱辛地學(xué)習(xí)各種多線程編程技術(shù)、解決各種并發(fā)問題呢? 因?yàn)椴l(fā)是整個(gè)分布式集群的基礎(chǔ),通過分布式集群不僅可以大...
摘要:實(shí)際工作并不是非此即彼,往往都是進(jìn)程線程結(jié)合的方式。操作系統(tǒng)會保證當(dāng)線程數(shù)不大于數(shù)目時(shí),不同的線程運(yùn)行于不同的上改善程序結(jié)構(gòu)。關(guān)于操作系統(tǒng)內(nèi)部如何創(chuàng)建銷毀進(jìn)程線程,即為什么這些操作進(jìn)程消耗會比線程大,還沒有搞明白。 一、淺層理解 進(jìn)程是資源分配的最小單位,線程是CPU分配的最小單位——簡單明了的說明了進(jìn)程與線程的區(qū)別特點(diǎn),然而在實(shí)際工作中并沒有什么卵用。 二、多個(gè)維度下,進(jìn)程與線程的優(yōu)...
摘要:對多線程程序,單核與多核如何工作相關(guān)的探討我們程序員在編碼的時(shí)候,涉及到技術(shù)方案時(shí),往往會忽略掉代碼對性能方面的影響,或者沒有足夠的敏感度來幫助自己判斷自己的技術(shù)方案對系統(tǒng)性能造成的影響。 對多線程程序,單核cpu與多核cpu如何工作相關(guān)的探討 我們程序員在編碼的時(shí)候,涉及到技術(shù)方案時(shí),往往會忽略掉代碼對性能方面的影響,或者沒有足夠的敏感度來幫助自己判斷自己的技術(shù)方案對系統(tǒng)性能造成的影...
摘要:對多線程程序,單核與多核如何工作相關(guān)的探討我們程序員在編碼的時(shí)候,涉及到技術(shù)方案時(shí),往往會忽略掉代碼對性能方面的影響,或者沒有足夠的敏感度來幫助自己判斷自己的技術(shù)方案對系統(tǒng)性能造成的影響。 對多線程程序,單核cpu與多核cpu如何工作相關(guān)的探討 我們程序員在編碼的時(shí)候,涉及到技術(shù)方案時(shí),往往會忽略掉代碼對性能方面的影響,或者沒有足夠的敏感度來幫助自己判斷自己的技術(shù)方案對系統(tǒng)性能造成的影...
摘要:最近聽很多面試的小伙伴說,網(wǎng)上往往是一篇一篇的多線程的文章,除了書籍沒有什么學(xué)習(xí)多線程的一系列文章。將此線程標(biāo)記為線程或用戶線程。 最近聽很多面試的小伙伴說,網(wǎng)上往往是一篇一篇的Java多線程的文章,除了書籍沒有什么學(xué)習(xí)多線程的一系列文章。但是僅僅憑借一兩篇文章很難對多線程有系統(tǒng)的學(xué)習(xí),而且面試的時(shí)候多線程這方面的知識往往也是考察的重點(diǎn),所以考慮之下決定寫一系列關(guān)于Java多線程的文章...
閱讀 3673·2021-09-27 14:02
閱讀 1793·2019-08-30 15:56
閱讀 1748·2019-08-29 18:44
閱讀 3281·2019-08-29 17:21
閱讀 491·2019-08-26 17:15
閱讀 1179·2019-08-26 13:57
閱讀 1244·2019-08-26 13:56
閱讀 2885·2019-08-26 11:30