1. 程式人生 > >並發編程(01)--多線程基礎

並發編程(01)--多線程基礎

create tac down 運行時 light cep 重新 tst 常用

1.關於多線程

1.1 線程與進程的區別

進程:系統中每一個正在運行的程序都是一個進程,每一個進程執行都有一個執行順序,該順序是一個執行路徑,或者叫一個控制單元

線程:是一組指令的集合,控制著進程的執行,一個進程中至少有一個線程

1.2 為什麽用多線程

使用多線程可以將執行時間長的程序中的任務放到後臺去處理,在一些需要等待的任務上如文件讀寫、網絡分發數據等,使用多線程就可以更好的利用CPU的資源,從而提高程序運行的效率

2. 線程的狀態

線程有5種狀態:新建、就緒、運行、阻塞、死亡,如下圖所示:

技術分享圖片

新建狀態:當new一個線程時, 例如new Thread(r),線程還沒有開始運行,此時線程處在新建狀態。 當一個線程處於新生狀態時,程序還沒有開始運行線程中的代碼

就緒狀態:一個新創建的線程並不自動開始運行,要執行線程,必須調用線程的start()方法。當線程對象調用start()方法即啟動了線程,start()方法創建線程運行的系統資源,並調度線程運行run()方法。當start()方法返回後,線程就處於就緒狀態。處於就緒狀態的線程並不一定立即運行run()方法,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間才可以運行線程。因為在單CPU的計算機系統中,不可能同時運行多個線程,一個時刻僅有一個線程處於運行狀態。因此此時可能有多個線程處於就緒狀態。對多個處於就緒狀態的線程是由java運行時系統的線程調度程序(thread scheduler)來調度的。

運行狀態:當線程競爭到CPU時間之後,執行run()方法,進入運行狀態

阻塞狀態:線程運行過程中,可能由於各種原因進入阻塞狀態:

1)線程通過調用sleep方法進入睡眠狀態;

2)線程調用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調用者;

3)線程試圖得到一個鎖,而該鎖正被其他線程持有;

4)線程在等待某個觸發條件;

所謂阻塞狀態是正在運行的線程沒有運行結束,暫時讓出CPU,這時其他處於就緒狀態的線程就可以獲得CPU時間,進入運行狀態。

死亡狀態:有兩種原因會導致線程進入死亡狀態:

1)run()方法執行完成正常死亡

2)發生異常終止了run()方法而進入死亡狀態

3. 創建線程的方法

3.1 繼承Thread類,重寫run()方法

class CreateThread extends Thread {
	
	publicvoid run() {
		// run方法中編寫 多線程需要執行的代碼
	}
}

3.2 實現Runnable接口,重寫run()方法

class CreateRunnable implements Runnable {

	@Override
	publicvoid run() {
		//run方法中編寫多線程需要執行的代碼
	}

}

3.3 匿名內部類方式

Thread thread = new Thread(new Runnable() {
			public void run() {
				//run方法中編寫多線程需要執行的代碼
			}
});

4. 常用的方法

4.1 join()

join():當線程B執行到了線程A的.join()方法時,B線程就會等待,等A線程都執行完畢,B線程才會執行,join可以用來臨時加入線程執行。

public class Thread002 {

	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					System.out.print("這個是t1線程:" + i +"\t");
				}
				System.out.println("\n--------------分割線------------------");
			}
		});

		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					t1.join();
					
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				for (int i = 0; i < 10; i++) {
					System.out.print("這個是t2線程:" + i+ "\t");
				}
				System.out.println("\n--------------分割線------------------");
			}
		});

		Thread t3 = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					t2.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				for (int i = 0; i < 10; i++) {
					System.out.print("這個是t3線程:" + i +"\t");
				}
				
			}
		});
		t1.start();
		t2.start();
		t3.start();

	}

}

4.2 sleep()、yield()

sleep():讓正在執行的線程休眠,因為使用sleep方法之後,線程是進入阻塞狀態的,只有當睡眠的時間結束,才會重新進入到就緒狀態,而就緒狀態進入到運行狀態,是由系統控制的,我們不可能精準的去幹涉它,所以如果調用Thread.sleep(1000)使得線程睡眠1秒,可能結果會大於1秒

public class SynTest {
    public static void main(String[] args) {
        new Thread(new CountDown(),"倒計時").start();
    }
}

class CountDown implements Runnable{
    int time = 10;
    public void run() {
        while (true) {
            if(time>=0){
                System.out.println(Thread.currentThread().getName() + ":" + time--);
                try {
                    Thread.sleep(1000);                                                    //睡眠時間為1秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

yield():和sleep方法類似,也是Thread類提供的一個靜態方法,可以讓正在執行的線程暫停,但是不會進入阻塞狀態,而是直接進入就緒狀態。相當於只是將當前線程暫停一下,然後重新進入就緒的線程池中,讓線程調度器重新調度一次。也會出現某個線程調用yield方法後暫停,但之後調度器又將其調度出來重新進入到運行狀態

public class SynTest {
    public static void main(String[] args) {
        yieldDemo ms = new yieldDemo();
        Thread t1 = new Thread(ms,"張三吃完還剩");
        Thread t2 = new Thread(ms,"李四吃完還剩");
        Thread t3 = new Thread(ms,"王五吃完還剩");
        t1.start();
        t2.start();
        t3.start();
    }
}
class yieldDemo implements Runnable{
    int count = 20;
    public void run() {
        while (true) {
                if(count>0){
                    System.out.println(Thread.currentThread().getName() + count-- + "個瓜");
                    if(count % 2 == 0){
                        Thread.yield();                  //線程讓步
                    }
            }
        }
    }
}

並發編程(01)--多線程基礎