程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 線程,java線程

線程,java線程

編輯:JAVA綜合教程

線程,java線程


本文原創,轉載請標明原處!

 

啟動與入口

Thread對象可操縱一個線程,而Runnable對象代表一個可被運行的對象,必須使用Thread對象的start()方法啟動線程。啟動後,會先運行Thread對象的run()方法,這個方法未被重寫時,就會執行Runnable對象的run()方法。

主線程的入口是main()靜態方法,子線程的入口是Thread的run()方法。下圖表示Thread與Runnable的區別:

 

運行與暫停

線程可以在運行中暫停,也可以從暫停中恢復運行,其暫停的目有如下列舉:

  • 周期性處理:如每秒更新時間的顯示,就需要每次更新完時間後,線程休眠1秒。
  • 定時處理:讓線程休眠至指定時間運行。
  • 事件處理:讓線程休眠至事件觸發的時候運行。
  • 通行限制:在特定代碼塊裡,只允許一定數量或具備一定條件的線程進入,被限制的線程暫停於關卡處。
  • 確保實時數據:多線程共用數據時,讀取數據的時間點到使用數據的時間點,會有一個時間差,因此使用數據時,該數據並不是實時數據。為了確保實時數據,就需要在使用時,只有一個線程在使用,其它需要用到該數據的線程就會暫停。

下圖表示,線程基本的暫停方式與恢復運行方式:

 

說明:圖中,虛線表示每次觸發時,只允許一條線程變化。Happen表示發生於其它線程,即異步觸發。

有一點不太明確,也不知道怎麼去測試,就是Auto Yield,這裡我猜想加上去的。猜想的依據是根據一篇文章《Java中的多線程你只要看這一篇就夠了》。文中寫道,並行與並發的概念與區別,思考了一下,並行是多個人同時處理各自的事,換句話說同一時刻可以處理多件事。而並發是一個人同時處理多件事,但實際上是做不到的,因為同一時刻只能處理一件事。不知道這裡,我有沒有思考有誤,如果是這樣,那麼同一時刻,就只處理著一條線程。

 

結束與監聽

線程結束分為自然結束與強制中止。

自然結束,是指線程啟動時的入口方法結束,自然結束分為正常結束和異常結束。異常結束是以某個異常拋出作為起點一直往上拋出,而正常結束,需要監聽到結束的標志後,處理關閉事項,需要處理上一段時間才能真正結束。

強制中止,在運行途中的任意位置結束,什麼時候中止,線程就什麼時候結束。可以使用stop()方法強制中止,也可以把把線程設置為目標線程的守護線程,這樣線程就會以目標線程結束而強制結束。強制中止,用於不需要維護重要數據的線程,即對重要數據不產生影響。

 

代碼示例1:主線程以子線程對象作為同步鎖,然後使用wait(...)方法,當子線程結束時,就會喚醒wait(...)方法,從而達到主線程監聽子線程的結束。

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(){
        public void run(){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子線程結束!");
        }
    };
    thread.start();
    
    // 相當於thread.join(),thread線程結束時,會調用thread.notifyAll()
    synchronized(thread){
        thread.wait();
    }
    System.out.println("主線程結束!");
    
    // 輸出結果:
    // 子線程結束!
    // 主線程結束!
}

實際上,join(...)方法裡面,用的就是這種方式監聽子線程的結束。因此,主線程使用join(...)方法後,子線程要切忌不能使用自己的線程對象作為同步鎖,那樣會造成死鎖。

 

代碼示例2:主線程調用子線程的interrupt()方法,使子線程在wait()方法裡拋出異常,同時還驗證了interrupt()使子線程從wait()方法中喚醒後,依然需要同步阻塞。 

public static void main(String[] args) throws InterruptedException {
    final Object lock = new Object();
    Thread[] threads = new Thread[5];

    for(int i=0; i<threads.length; i++){
        final int num = i + 1;
        Thread thread = new Thread(){
            public void run(){
                synchronized(lock){
                    try {
                        System.out.println("線程" + num + " -> 進入等待!");
                        lock.wait();
                    } catch (InterruptedException e) {
                        // e.printStackTrace();
                        System.out.println("線程" + num + " -> " + e);
                    }
                    System.out.println("線程" + num + " -> 退出等待!");
                    
                    try {
                        System.out.println("線程" + num + " -> 進入睡眠!");
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // e.printStackTrace();
                        System.out.println("線程" + num + " -> " + e);
                    }
                    System.out.println("線程" + num + " -> 睡眠結束,退出同步塊!");
                    
                    Thread.currentThread().stop();
                    System.out.println("線程" + num + " -> 結束沒有?");
                }
            }
        };
        thread.start();
        threads[i] = thread;
    }

    System.out.println("主線程 -> 等待2秒!");
    Thread.sleep(2000);
    System.out.println("主線程 -> 中止所有線程!");
    
    for(int i=0; i<threads.length; i++){
        threads[i].interrupt();
    }

    for(int i=0; i<threads.length; i++){
        threads[i].join();
    }
    System.out.println("主線程 -> 中止所有線程結束!");
    
    /*
         輸出結果:
        線程1 -> 進入等待!
        線程4 -> 進入等待!
        主線程 -> 等待2秒!
        線程3 -> 進入等待!
        線程2 -> 進入等待!
        線程5 -> 進入等待!
        主線程 -> 中止所有線程!
        線程1 -> 退出等待!
        線程1 -> 進入睡眠!
        線程1 -> 睡眠結束,退出同步塊!
        線程4 -> 退出等待!
        線程4 -> 進入睡眠!
        線程4 -> 睡眠結束,退出同步塊!
        線程3 -> 退出等待!
        線程3 -> 進入睡眠!
        線程3 -> 睡眠結束,退出同步塊!
        線程2 -> 退出等待!
        線程2 -> 進入睡眠!
        線程2 -> 睡眠結束,退出同步塊!
        線程5 -> 退出等待!
        線程5 -> 進入睡眠!
        線程5 -> 睡眠結束,退出同步塊!
        主線程 -> 中止所有線程結束!
     */
}

  

代碼示例3:子線程作為主線程的守護線程,因主線程的結束而強制中止。

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(){
        public void run(){
            boolean run = true;
            while(run){
                System.out.println("子線程 -> 運行中……");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("子線程 -> 正常退出!");
        }
    };
    thread.setDaemon(true);
    thread.start();
    
    System.out.println("主線程 -> 2秒後結束");
    Thread.sleep(2000);
    System.out.println("主線程 -> 結束");
    
    /*
        運行結果:
        主線程 -> 2秒後結束
        子線程 -> 運行中……
        子線程 -> 運行中……
        子線程 -> 運行中……
        子線程 -> 運行中……
        子線程 -> 運行中……
        主線程 -> 結束
     */
}

 

 待續更新……

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved