java支持多线程吗_Java多线程之一
進(jìn)程與線(xiàn)程
進(jìn)程
進(jìn)程是進(jìn)程實(shí)體的運(yùn)行過(guò)程,是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位,比如我們windows電腦上運(yùn)行的一個(gè)程序就是一個(gè)進(jìn)程。在傳統(tǒng)進(jìn)程中進(jìn)程是資源分配和調(diào)度的一個(gè)基本單位,在后來(lái)引入線(xiàn)程概念后,進(jìn)程就變成了資源分配的基本單位但不是調(diào)度的基本單位。
為什么要有線(xiàn)程
在說(shuō)線(xiàn)程前,總結(jié)下進(jìn)程的特點(diǎn):
進(jìn)程是一個(gè)可擁有資源的獨(dú)立單位;
進(jìn)程是一個(gè)可獨(dú)立調(diào)度和分派的基本單位。
這樣來(lái)看的話(huà)好像是沒(méi)什么問(wèn)題,但是在多任務(wù)環(huán)境中,不可能說(shuō)讓所有任務(wù)排隊(duì),前面的處理完了才處理后面的任務(wù)。如果要讓用戶(hù)感覺(jué)到任務(wù)都是一起執(zhí)行的,那么就必須在進(jìn)程之間頻繁切換。問(wèn)題在于如果要進(jìn)行進(jìn)程的切換需要做很多的工作,必須要保存好當(dāng)前CPU的上下文,好讓CPU下次被分配到當(dāng)前進(jìn)程時(shí)可以繼續(xù)往前執(zhí)行,然后還需要設(shè)置新的進(jìn)程的CPU上下文,在這個(gè)過(guò)程中會(huì)花費(fèi)很多時(shí)間。由于這個(gè)原因就限制了系統(tǒng)中進(jìn)程數(shù)目不能多。
為了解決這個(gè)限制,后來(lái)提出將進(jìn)程的兩個(gè)屬性分開(kāi),由操作系統(tǒng)分開(kāi)處理,即對(duì)于作為調(diào)度和分派的基本單位,但不同時(shí)作為擁有資源的單位;而對(duì)于擁有資源的基本單位,又不對(duì)其進(jìn)行頻繁的切換。正是在這種思想的指導(dǎo)下,形成了線(xiàn)程的概念。
線(xiàn)程
在多線(xiàn)程操作系統(tǒng)中中,通常是在一個(gè)進(jìn)程中包括多個(gè)線(xiàn)程,每個(gè)線(xiàn)程都是獨(dú)立調(diào)度和分派的基本單位。資源由進(jìn)程來(lái)?yè)碛?#xff0c;線(xiàn)程不擁有資源。同一個(gè)進(jìn)程之間的線(xiàn)程切換不會(huì)導(dǎo)致進(jìn)程的切換,只有不同進(jìn)程間的線(xiàn)程切換才會(huì)導(dǎo)致進(jìn)程切換。而且線(xiàn)程的切換則僅需保存和設(shè)置少量寄存器內(nèi)容,不會(huì)同進(jìn)程切換需求創(chuàng)建和銷(xiāo)毀進(jìn)程控制塊等,所以非常迅速,所以其十分適合高并發(fā)環(huán)境。
線(xiàn)程的狀態(tài)(Java)
public enum State {
NEW,//新建 線(xiàn)程被創(chuàng)建,但是沒(méi)有調(diào)用start方法
RUNNABLE,//可運(yùn)行 表示當(dāng)前線(xiàn)程可以運(yùn)行,但實(shí)際是否運(yùn)行有cpu決定
BLOCKED,//阻塞 其他線(xiàn)程獲得鎖,當(dāng)前線(xiàn)程被阻塞在獲得鎖處
WAITING,//等待 等待其他條件成熟進(jìn)入可運(yùn)行狀態(tài)
TIMED_WAITING,//計(jì)時(shí)等待 在一個(gè)指定時(shí)間內(nèi)等待,超時(shí)后放棄
TERMINATED;//終止 線(xiàn)程執(zhí)行完畢
}
線(xiàn)程的創(chuàng)建方式
Thread
繼承Thread類(lèi):
class TestThread extends Thread{
@Override
public void run() {
super.run();
//do working
}
}
Runnable
實(shí)現(xiàn)Runnable接口:
static class TestRunnale implements Runnable{
@Override
public void run() {
//do working
}
}
public static void main(String[] args) {
TestRunnale runnale = new TestRunnale();
Thread thread = new Thread(runnale);
thread.start();
}
線(xiàn)程的中斷
不安全的中斷
在Thread的api中提供了一些終止線(xiàn)程的方法,比如stop(),suspend(),resume(),但是這些方法目前在JDK中已經(jīng)被標(biāo)記位過(guò)時(shí),因?yàn)檫@些方法具有死鎖傾向,已經(jīng)被明確表示不支持使用。
中斷線(xiàn)程API
interrupt() 中斷線(xiàn)程,本質(zhì)是將線(xiàn)程的中斷標(biāo)志位設(shè)為true,其他線(xiàn)程向需要中斷的線(xiàn)程打個(gè)招呼。是否真正進(jìn)行中斷由線(xiàn)程自己決定。
isInterrupted() 線(xiàn)程檢查自己的中斷標(biāo)志位
靜態(tài)方法Thread.interrupted() 將中斷標(biāo)志位復(fù)位為false
中斷標(biāo)志位
自定義一個(gè)Boolean類(lèi)型的中斷標(biāo)志位,提供一個(gè)中斷方法,線(xiàn)程一直循環(huán)檢測(cè)該標(biāo)志位,標(biāo)志位被設(shè)置為退出狀態(tài)是終止線(xiàn)程。
public class FlagCancel {
static class Flag extends Thread{
//中斷標(biāo)志
public static boolean flag = false;
@Override
public void run() {
int i = 0;
while(!flag){
System.out.println(i++);
if(i>=3){
try {
Thread.sleep(200);
//interrupt();
if(i == 10)
cancel();//修改中斷狀態(tài),退出線(xiàn)程
System.out.println("thread:" + isInterrupted());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("cancel...");
}
}
}
public static void cancel(){
flag = true;
}
}
public static void main(String[] args) {
Flag test = new Flag();
test.start();
test.setPriority(10);//這里的設(shè)置優(yōu)先級(jí)其實(shí)沒(méi)什么用。cpu不會(huì)理你的。。。
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main:" + test.isInterrupted());//這里屬于主線(xiàn)程(main)
}
}
正常來(lái)說(shuō)上面的形式?jīng)]有什么問(wèn)題,我們寫(xiě)代碼的時(shí)候,提供一個(gè)修改中斷為狀態(tài)的方法,并根據(jù)我們自己的業(yè)務(wù)邏輯來(lái)定義什么時(shí)候中斷,但是如果我們手動(dòng)設(shè)置中斷就有問(wèn)題了,將上面代碼中注釋的interrupt();打開(kāi)。interrupt()方法是用來(lái)中斷線(xiàn)程的,但是在上面的邏輯中即使調(diào)用了該方法也不會(huì)立即中斷,而必須要等待中斷為被修改后才能退出。
安全的中斷
上面介紹了中斷相關(guān)的api和使用中斷標(biāo)志位來(lái)中斷線(xiàn)程,但是中斷標(biāo)記位無(wú)法捕獲異常情況。但是isInterrupted()方法會(huì)一直檢查線(xiàn)程的中斷狀態(tài),所以我們可以用這個(gè)方法來(lái)實(shí)現(xiàn)安全的中斷。
public class SafeInterrupt extends Thread {
private boolean flag = false;
@Override
public void run() {
int i = 0;
System.out.println(Thread.currentThread().getName() + ":" +Thread.currentThread().isInterrupted());
while (!flag && !Thread.currentThread().isInterrupted()) {
System.out.println(i++);
try {
synchronized (this) {
if (i > 3) {
//Thread.sleep(1000 * 60 * 60 * 24);
wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 這里必須將需要中斷的線(xiàn)程作為參數(shù)傳過(guò)來(lái)
* 用以進(jìn)行中斷
* @param t(Thread)
*/
public void cancel(Thread t) {
System.out.println("ready stop currentThread...");
flag = true;
//將需要中斷的線(xiàn)程的中斷標(biāo)志位設(shè)置為true
t.interrupt();
System.out.println(t.getName() + ":" + t.isInterrupted());
}
public static void main(String[] args) throws InterruptedException {
SafeInterrupt safeInterrupt = new SafeInterrupt();
safeInterrupt.start();
Thread.sleep(100);
safeInterrupt.cancel(safeInterrupt);
}
}
不可中斷的情況
好了,到現(xiàn)在我們已經(jīng)可以安全的處理線(xiàn)程的中斷了,但是還沒(méi)完,因?yàn)椴皇撬械木€(xiàn)程都是會(huì)響應(yīng)中斷的。比如IO的read()/write() 等就不會(huì)響應(yīng)中斷。而如果我們想不讓其繼續(xù)阻塞的話(huà)就需要我們手動(dòng)的關(guān)閉底層的套接字。
public class CloseSocket extends Thread {
private Socket socket;
private InputStream in;
public CloseSocket(Socket socket, InputStream in) {
this.socket = socket;
this.in = in;
}
//重寫(xiě)中斷方法 在中斷線(xiàn)程時(shí)中斷套接字
@Override
public void interrupt() {
try {
//關(guān)閉底層套接字
socket.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
//中斷線(xiàn)程
super.interrupt();
}
}
}
還有想死鎖之類(lèi)的不響應(yīng)中斷的情況用代碼已經(jīng)基本解決不了了,只能檢查代碼修改重啟服務(wù)器啦。
總結(jié)
以上是生活随笔為你收集整理的java支持多线程吗_Java多线程之一的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android edittext 正则限
- 下一篇: java如何把png转换成jpg_Jav