一、線程概述
線程是在程序中獨(dú)立并發(fā)的執(zhí)行流缸沃,相比于進(jìn)程恰起,線程具有更高的性能,多個(gè)線程可以共享一個(gè)進(jìn)程虛擬空間和泌,線程之間共享內(nèi)存非常方便村缸,可以擁有很高的并發(fā)。
二武氓、線程的創(chuàng)建和啟動(dòng)
2.1 繼承Thread類創(chuàng)建線程類
通過繼承Thread類來創(chuàng)建啟動(dòng)多線程的步驟如下:
(1)定義Thread的子類梯皿,重寫run方法
(2)創(chuàng)建Thread子類的實(shí)例
(3)通過start來啟動(dòng)線程
Thread.currentThread()可以返回當(dāng)前正在執(zhí)行的線程對(duì)象
getName()可以返回線程的名字
public class FirstThread extends Thread{
public void run()
{...}
}
new FirstThread().start();
2.2 實(shí)現(xiàn)Runnable接口創(chuàng)建線程類
通過Runnable接口來創(chuàng)建并啟動(dòng)多線程的步驟如下:
(1)定義Runnable的實(shí)現(xiàn)類,并且重寫run方法
(2)創(chuàng)建Runnable實(shí)現(xiàn)類的實(shí)例县恕,并且以此實(shí)例作為Thread的target來創(chuàng)建Thread對(duì)象
public class SecondThread implements Runnable
{
public void run()
{...}
}
new Thread(st,'name').start();
采用Runnable接口的方式來創(chuàng)建的多條線程可以共享線程類的實(shí)例屬性东羹。
采用Runnable接口方式來創(chuàng)建的線程只能通過Thread.currentThread()來獲取當(dāng)前線程,而不能通過this
3 線程的生命周期
- 新建狀態(tài):new了一個(gè)線程之后
- 就緒狀態(tài):調(diào)用了start之后(永遠(yuǎn)不要直接調(diào)用run方法)
- 運(yùn)行狀態(tài):線程獲得CPU忠烛,開始運(yùn)行run方法之后
- 阻塞狀態(tài):調(diào)用sleep,調(diào)用阻塞式IO方法属提,等待通知,程序調(diào)用了suspend方法等,都會(huì)使線程進(jìn)入阻塞狀態(tài)冤议。
- 線程死亡:run()執(zhí)行完畢斟薇,拋出未捕獲的Exception和Error,或者調(diào)用該程序的stop()方法來結(jié)束該線程。
可以通過線程的isAlive方法來判斷線程是否死亡
不要試圖對(duì)一個(gè)已經(jīng)死亡的線程調(diào)用start方法
4 控制線程
4.1 join線程
某個(gè)線程調(diào)用另一個(gè)線程的join方法以后恕酸,該線程將被阻塞堪滨,直到被join的線程執(zhí)行完畢以后為止。
- join()
- join(long millis)
- join(long millis,int nanos)
4.2 后臺(tái)線程
后臺(tái)線程有個(gè)特征:如果前臺(tái)線程都死亡蕊温,則后臺(tái)線程會(huì)自動(dòng)死亡袱箱。
通過調(diào)用Thread的setDaemon(true)的時(shí)候,就可以將其設(shè)為后臺(tái)線程义矛。
可以通過isDaemon()來判斷是否是后臺(tái)線程
4.3 線程睡眠Sleep
- Thread.sleep(long millis)
- Thread.sleep(long millis, int nanos)
4.4 線程讓步y(tǒng)ield
yield方法不會(huì)阻塞該線程发笔,而是轉(zhuǎn)入就緒狀態(tài),讓線程調(diào)度器重新調(diào)度一次凉翻。
- Thread.yield
4.5 改變線程優(yōu)先級(jí)
- Thread.setPriority(int newPriority)
優(yōu)先級(jí)值在1~10之間了讨,也可以使用MAX_PRIORITY(10),MIN_PRIORITY(1),NORM_PRIORITY(5)
5 線程的同步
5.1同步代碼塊
synchronized(obj){ 同步代碼塊 }
5.2同步方法
public synchronized void draw(double drawAmount)
5.3釋放同步監(jiān)視器的鎖定
以下情況會(huì)釋放:
- 代碼塊執(zhí)行完畢
- break return
- 拋出錯(cuò)誤或者異常
- 程序執(zhí)行了同步監(jiān)視器對(duì)象的wait()方法
5.4 同步鎖
常用的有可重用鎖ReentrantLock,可重用的意思是說,對(duì)已經(jīng)加鎖的ReentrantLock可以再次上鎖制轰,該對(duì)象會(huì)維持一個(gè)計(jì)數(shù)器來記錄量蕊。
public class Accout
{
private final ReetrantLock lock = new ReentrantLock();
public void draw(double drawAmout)
{
lock.lock();
try
{
//臨界區(qū)
}
finally
{
lock.unlock();
}
}
}
5.5 死鎖
當(dāng)兩個(gè)線程相互等待對(duì)方釋放同步監(jiān)視器就會(huì)發(fā)生死鎖。
6 線程通信
6.1 線程的協(xié)調(diào)運(yùn)行
Object類提供的wait(), notify(),notifyAll()三個(gè)方法艇挨,必須由同步監(jiān)視器來調(diào)用:
- 對(duì)于使用synchronized修飾的同步方法残炮,該類的默認(rèn)實(shí)例this就是同步監(jiān)視器
- 對(duì)于使用synchronized修飾的代碼塊,后面括號(hào)里的對(duì)象就是同步監(jiān)視器
6.2 使用條件變量進(jìn)行控制協(xié)調(diào)
如果程序不使用synchronized關(guān)鍵字來保持同步缩滨,而是直接使用Lock對(duì)象來保持同步势就,則系統(tǒng)中不存在隱式的同步監(jiān)視器對(duì)象。Java提供了一個(gè)Condition類來保持協(xié)調(diào)脉漏。
- await()
- signal()
- signalAll()
public class Account
{
private final Lock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
####6.3 使用管道流
如果兩條線程之間需要更多的信息交互苞冯,則可以考慮使用管道流。
PipedWriter pw = null;
PipedReader pr = null;
try
{
pw = new PipedWriter();
pr = new PipedReader();
pw.connect(pr);
new WriterThread(pw).start();
new ReaderThread(pr).start();
}
###7 Callable和Future
Callable看起來像是Runnable的接口和增強(qiáng)版侧巨,call方法是其線程執(zhí)行體舅锄,但是比run()方法更強(qiáng)大:可以有返回值,可以拋出異常
class RtnThread implements Callable<Integer>
{
public Integer call(){
return i
}
}
public class CallableTest
{
public static void main(String[] args)
{
RtnThread rt = new RtnThread();
FutrueTask<Integer> task = new FutureTask<Integer>(rt);
new Thread(task,'name').start();
System.out.println(task.get());
}
}
###8 線程池
略過
###9 線程相關(guān)類
####9.1 ThreadLocal類
ThreadLocal類是線程局部變量的意思司忱,就是為每一個(gè)使用該變量的線程都提供一個(gè)變量值的副本皇忿。從而避免沖突。
ThreadLocal提供了三個(gè)public方法:
* T get()
* void remove()
* void set(T value)
>如果需要進(jìn)行多個(gè)線程之間的資源共享坦仍,就需要使用同步機(jī)制鳍烁,如果只是需要隔離多個(gè)線程之間的共享沖突,則可以使用ThreadLocal
####9.2 線程包裝不安全的集合
Java集合中介紹的ArrayList繁扎,LinkedList, HashSet, TreeSet, HashMap都是線性不安全的幔荒『觯可以使用Collections的方法來將其變成線程安全:
SynchronizedCollection/List/Map/Set/SortedMap/SortedSet
####9.3 線程安全的集合類
JDK1.5開始,java.util.concurrent包下提供了ConcurrentHashMap, ConcurrentLinkedQueue爹梁。