發(fā)布于:2021-01-21 11:39:03
0
155
0
本文講述了線程的故事,并解釋了它的主要優(yōu)點(diǎn)、缺點(diǎn)和用途。您將從熟練的Java程序員那里學(xué)習(xí)如何使用擴(kuò)展線程類和實(shí)現(xiàn)可運(yùn)行接口來創(chuàng)建線程。
螺紋的優(yōu)點(diǎn)
縮短開發(fā)時(shí)間。
降低維護(hù)成本。
提高復(fù)雜應(yīng)用程序的性能。
有助于提高用戶界面的響應(yīng)能力。
用于服務(wù)器應(yīng)用程序,以提高高吞吐量和資源利用率。
并行化任務(wù)。
如果線程無法執(zhí)行任務(wù)使用CPU的所有計(jì)算資源(因?yàn)橹噶钜蕾囉诒舜说慕Y(jié)果),運(yùn)行另一個線程可以避免這些線程處于空閑狀態(tài)。
利用多處理器系統(tǒng)。
螺紋的缺點(diǎn)
在共享硬件資源(如緩存或轉(zhuǎn)換查找緩沖區(qū)(TLB))時(shí),多個線程可能會相互干擾。
單個線程的執(zhí)行時(shí)間可能會降低,即使只有一個線程在執(zhí)行。這是由于適應(yīng)線程切換硬件所需的較慢的頻率和/或額外的流水線級。
軟件對多線程的硬件支持更為明顯,因此需要對應(yīng)用程序和操作系統(tǒng)進(jìn)行比多處理更多的更改。
螺紋的用途
Java應(yīng)用程序是自然線程化的。運(yùn)行時(shí)環(huán)境使用一個線程中的main()方法開始執(zhí)行程序。垃圾回收發(fā)生在另一個線程中。屏幕更新發(fā)生在第三個線程中??赡苓€有其他線程也在運(yùn)行,主要與虛擬機(jī)的行為有關(guān)。所有這些都發(fā)生在程序員身上。有時(shí)您只關(guān)心主線程中發(fā)生了什么,其中包括程序的main()方法。如果是這種情況,您可能根本不需要擔(dān)心線程問題。
多線程的主要目的是提供同時(shí)執(zhí)行程序的兩個或多個部分,以盡可能多地利用CPU時(shí)間。多線程程序包含兩個或多個可以并發(fā)運(yùn)行的部分。這樣一個程序的每一部分都稱為線程。每個線程都有一個單獨(dú)的執(zhí)行路徑。這樣一個程序就可以同時(shí)執(zhí)行兩個或多個任務(wù)。
線程是輕量級進(jìn)程;它們共享相同的地址空間。在多線程環(huán)境中,程序最大限度地利用CPU,以便將空閑時(shí)間保持在最小值。
執(zhí)行異步或后臺處理。
線程
Thread類是程序中執(zhí)行的線程。Java虛擬機(jī)允許應(yīng)用程序同時(shí)運(yùn)行多個執(zhí)行線程。以下是最重要的幾點(diǎn):
每個線程都有一個優(yōu)先級。優(yōu)先級較高的線程在優(yōu)先級較低的線程之前執(zhí)行。
每個線程也可以標(biāo)記為守護(hù)進(jìn)程,也可以不標(biāo)記為守護(hù)進(jìn)程。
創(chuàng)建新的執(zhí)行線程有兩種方法。一種是將類聲明為線程的子類。
另一種創(chuàng)建線程的方法是聲明實(shí)現(xiàn)可運(yùn)行接口的類。
線程類提供了用于在線程類上創(chuàng)建和執(zhí)行操作的構(gòu)造函數(shù)和方法。線程類擴(kuò)展了Object類并實(shí)現(xiàn)了Runnable接口。
線程類的構(gòu)造函數(shù)
線程()
線程(String str)
線程(Runnable r)
線程(Runnable r,String str)
Thread類定義了許多用于管理線程的方法。其中一些是:
方法 | 描述 |
setName() | 給線程起個名字 |
getName() | 返回線程的名稱 |
getPriority() | 返回線程的優(yōu)先級 |
isAlive() | 檢查線程是否仍在運(yùn)行 |
join() | 等待線程結(jié)束 |
run() | 線程的入口點(diǎn) |
sleep() | 將線程掛起指定的時(shí)間 |
start() | 通過調(diào)用run()方法啟動線程 |
有兩種創(chuàng)建線程的方法:
擴(kuò)展線程類
實(shí)現(xiàn)Runnable接口
1.擴(kuò)展線程類
通過擴(kuò)展Thread類的新類創(chuàng)建線程,并創(chuàng)建該類的實(shí)例。擴(kuò)展類必須重寫run()方法,該方法是新線程的入口點(diǎn)。
public class MyThread extends Thread{ public void run() { System.out.println("Thread started running.."); } public static void main( String args[] ) { MyThread mt = new MyThread(); mt.start(); } }
在這種情況下,我們必須重寫run(),然后使用start()方法啟動并運(yùn)行線程。同樣,當(dāng)您創(chuàng)建MyThread類對象時(shí),由于它是超類,因此也將調(diào)用Thread類構(gòu)造函數(shù),因此MyThread類對象充當(dāng)Thread類對象。
我們直接調(diào)用run()方法,而無需使用start()方法。
public static void main( String args[] ) { MyThread mt = new MyThread(); mt.start(); mt.start(); //Exception thrown }
不會為該線程分配新的調(diào)用堆棧,它將開始在當(dāng)前調(diào)用堆棧(即主線程的調(diào)用堆棧)中運(yùn)行。因此,多線程將不存在。
我們啟動一個線程兩次。
線程不能啟動兩次。如果您嘗試這樣做,將拋出IllegalThreadStateException。
public static void main( String args[] ) { MyThread mt = new MyThread(); mt.start(); mt.start(); //Exception thrown }
當(dāng)線程處于運(yùn)行狀態(tài)時(shí),您嘗試重新啟動它,或者任何方法嘗試使用start()方法再次調(diào)用該線程,都會引發(fā)異常。
2.實(shí)現(xiàn)可運(yùn)行接口
創(chuàng)建線程的最簡單方法是創(chuàng)建一個實(shí)現(xiàn)可運(yùn)行接口的類。在實(shí)現(xiàn)runnable接口之后,該類需要實(shí)現(xiàn)run()方法,即
公共無效run()
run()方法將并發(fā)線程引入程序。當(dāng)run()返回時(shí),該線程將結(jié)束。
您必須在run()方法中為線程指定代碼。
run()方法可以調(diào)用其他方法,可以使用其他類并聲明變量,就像其他任何普通方法一樣。
MyThread類實(shí)現(xiàn)Runnable
public void run() { System.out.println("Thread started running.."); } public static void main(String args[]) { MyThread mt = new MyThread(); Thread t = new Thread(mt); t.start(); } }
要調(diào)用run()方法,請使用start()方法。在調(diào)用start()時(shí),會向線程提供一個新堆棧,并調(diào)用run()方法將新線程引入程序
結(jié)束線程
線程結(jié)束的原因如下:
當(dāng)run()方法完成其執(zhí)行時(shí)線程結(jié)束。
當(dāng)線程拋出程序中未捕獲的異?;蝈e誤時(shí)。
Java程序完成或結(jié)束。
另一個線程調(diào)用stop()方法。
線程同步
當(dāng)多個線程試圖訪問共享資源時(shí),我們需要確保資源一次只能由一個線程使用。實(shí)現(xiàn)這一點(diǎn)的過程稱為同步。
Java中的synchronization關(guān)鍵字創(chuàng)建了一個稱為critical section的代碼塊。
通過使用這個,一次只有一個線程可以訪問該方法,第二個調(diào)用將被阻止,直到第一個調(diào)用返回或在內(nèi)部調(diào)用wait()同步方法。
語法
synchronized (object) { // Statement to be synchronized }
使用同步
如果不使用同步,讓兩個或多個線程同時(shí)訪問共享資源,將導(dǎo)致扭曲的結(jié)果。
下面是一個示例:假設(shè)我們有兩個不同的線程T1和T2,T1開始執(zhí)行并將某些值保存到文件示例.txt當(dāng)T1返回時(shí),它將用于計(jì)算一些結(jié)果。同時(shí),T2開始,在T1返回之前,T2更改T1保存在文件中的值示例.txt(sample.txt是共享資源)。現(xiàn)在很明顯,T1會給出錯誤的結(jié)果。
同步被引入以防止此類問題的發(fā)生。如果我們在上述情況下使用同步,那么一旦T1開始使用示例.txt文件,此文件將被鎖定(鎖定模式),在T1返回之前,其他線程將無法訪問或修改它。
僵局
死鎖描述了兩個或多個線程被永遠(yuǎn)阻塞,互相等待的情況。當(dāng)多個線程需要相同的鎖但以不同的順序獲得它們時(shí),就會發(fā)生死鎖。Java多線程程序可能會遇到死鎖情況,因?yàn)殛P(guān)鍵字synchronized會導(dǎo)致執(zhí)行線程在等待與指定對象關(guān)聯(lián)的鎖或監(jiān)視器時(shí)阻塞。
為了避免死鎖,應(yīng)確保在獲取多個鎖時(shí),在所有線程中總是以相同的順序獲取鎖。
Java程序員在這里討論的關(guān)于線程的每一點(diǎn)都是為了讓您了解線程及其用法以及缺點(diǎn)和好處。
作者介紹