1. 程式人生 > >java並發-線程

java並發-線程

pre java 方式 throw 關閉 多個 add current 後臺線程

前言

近來時間比較充裕,正好又看了一遍《實戰java高並發程序設計》,故而對java並發一些知識進行下總結,算是溫故而知新吧。

一,線程基礎

1,新建線程

一般有兩種實現方式實現Runnable接口或繼承Thread類(Thread類本身也是實現Runnable接口)

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1=new TestThread();
        Thread t2=new TestThread();
        Thread t3
=new Thread(new TestThreadImpl()); Thread t4=new Thread(new TestThreadImpl()); t1.start(); t2.start(); t3.start(); t4.start(); } } class TestThread extends Thread{ @Override public void run() { System.out.println("hello word"); } }
class TestThreadImpl implements Runnable{ @Override public void run() { System.out.println("hello word 2"); } }

2,線程的終止

一般來說線程在執行完畢後就會結束無須手動關閉,但凡是總有例外一下服務端的後臺線程可能會常駐系統,比如它們本身就是一個無限循環,用於提供默寫服務。

Thread 提供了一個被標註為廢棄的方法stop();因為stop()方法過於暴力,強行把執行一般的線程終止,這樣可能會引起一些數據不一致的問題。《實戰java高並發程序設計》中給出了一個的解決方案,用一個一個自定義的stop並且需要自行決定何時退出

class ChangeObjectThread extends Thread{
    volatile boolean stopme=false;
    public void stopMe(){
        stopme=true;
    }
    @Override
    public void run() {
        while(true){
            if(stopme){
                break;
            }
            //synchromized handle data

        }
    }
}

3,線程中斷interrupt

嚴格來講,線程中斷並不會讓線程立即退出,而是給線程發送一個通知,告知目標線程 ,有人希望你退出了。至於目標線程街道通知後如何處理,則完全有線程自行決定,如果無條件退出那麽又遇到和stop()相同的問題了。

public void interrupt() //中斷線程
public boolean isInterrupted()//判斷是否被中斷
public static boolean interrupted()//判斷是否被中斷,並清除當前中斷狀態
public class Test {
    public static Object o = new Object();

    public static void main(String[] args) throws Exception {
        Thread t1 = new TestThread();
        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
    }
}

class TestThread extends Thread {
    @Override
    public void run() {
        int i=0;
        while (!isInterrupted()) {
            i++;
            System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);  
        }
    }
}

另:當線程由於被調用了sleep(), wait(), join()等方法而進入阻塞狀態;若此時調用線程的interrupt()將線程的中斷標記設為true。由於處於阻塞狀態,中斷標記會被清除,同時產生一個InterruptedException異常,這時就要用合適的方式處理InterruptedException了

4,Object 等待(wait)和通知(notify)

這兩個方法是由Object類提供的,並不是在Thread中的。當一個對象實例調用了wait()方法後,當前線程就會在這個對象上等待。如:線程A中調用了obj.wait()方法,那麽線程A就會停止繼續執行,而轉為等待狀態,直到調用了obj.notify()方法為止。

wait(),notify()方法的調用鼻血包含在對應的synchronized語句中,也就是要先獲得目標對象鎖資源。調用了wait後,會釋放鎖資源。

public class Test {
    public static Object o = new Object();

    public static void main(String[] args) throws Exception {
        Thread t1 = new TestThread();
        Thread t2 = new TestThread();
        Thread t3 = new TestThread();
        Thread t4 = new TestThreadNotify();
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}

class TestThread extends Thread {
    @Override
    public void run() {
        synchronized (Test.o) {
            try {
                System.out.println(Thread.currentThread().getName()+"waiting....");
                Test.o.wait();
                System.out.println(Thread.currentThread().getName()+"start....");
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"stop....");
        }
    }
}

class TestThreadNotify extends Thread {
    @Override
    public void run() {
        synchronized (Test.o) {
            System.out.println("TestThreadNotify start....");
            try {
                Test.o.notifyAll();
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("TestThreadNotify stop....");
        }
    }
}
}
Thread-0waiting....
TestThreadNotify start....
TestThreadNotify stop....
Thread-2waiting....
Thread-1waiting....
Thread-0start....
Thread-0stop....

5,等待線程結束(join)和謙讓(yield)


很多時候,一個線程的輸入可能非常依賴於另外一個或者多個線程的輸出,此時,這個線程就需要等待依賴線程執行完畢,才能繼續執行。JDK 提供了join()操作來實現這個功能,如下所示,顯示了2個join()方法:

public final void join() throws InterruptedException

public final synchronized void join(long millis) throws InterruptedException

第一個join()方法表示無限等待,它會一直阻塞當前線程,直到目標線程執行完畢。

第二個方法給出了一個最大等待時間,如果超過給定時間目標線程還在執行,當前線程也會因為“等不及了”,而繼續往下執行。

join()的本質是讓調用線程wait()在當前線程對象實例上;

public class Test {
    public volatile static int i = 0;
    public static class AddThread extends Thread {
        @Override
        public void run() {
            for (i = 0; i < 10000000; i++);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        AddThread at = new AddThread();
        at.start();
        at.join();
        System.out.println(i);

    }

}

主函數中,如果不使用join()等待AddThread ,那麽得到的i 很可能是0或者一個非常小的數字。因為AddThread 還沒開始執行,i 的值就已經被輸出了。但在使用join()方法後,表示主線程願意等待AddThread 執行完畢,跟著AddThread 一起往前走,故在join()返回時,AddThread 已經執行完成,故i 總是10000000

yiead()

這是一個靜態方法,一旦執行,它會使當前線程讓出CPU 。但要註意,讓出CPU 並不表示當前線程不執行了。當前線程在讓出CPU 後,還會進行CPU 資源的爭奪,但是是否能夠再次被分配到,就不一定了

待續

java並發-線程