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