00 01Java高級之線程常用操作方法

1 線程命名的取得

多線程的主要操作方法都在Thread類中定義的。

首先多線程的運行狀態是不確定的,那麼在程序的開發之中爲了可以獲取到一些需要使用到的線程就只能依靠線程的名字來進行操作。所以線程的名字是一個至關重要的概念,這樣在Thread類之中就提供有線程名稱的處理。
(1)構造方法:public Thread​(Runnable target, String name);
(2)設置名字:public final void setName​(String name);
(3)取得名字:public final String getName();
對於線程對象的獲得是不可能只是依靠一個this來完成的,因爲線程的狀態不可控,但是有一點是明確的,所有的線程對象一定要執行run()方法,那麼這個時候可以考慮獲取當前線程,在Thread類裏面提供有獲取當前線程的方法。
(1)獲取當前線程:public static Thread currentThread()
範例:觀察線程的命名操作

class MyThread implements Runnable{

	@Override
	public void run() {
		for(int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "run: i = " + i);
		}
	}

	
	
}

public class ThreadDemo {

	public static void main(String[] main)throws Exception {
		new Thread(new MyThread(), "Thread-A").start();
		new Thread(new MyThread()).start();
		new Thread(new MyThread(), "Thread-B").start();
		
	}
}

當開發者爲線程設置名字的時候就使用設置的名字,而如果沒有設置名字,則會自動生成一個不重複的名字。這種自動的屬性命名主要是依靠了static屬性完成的,在Thread類裏面定義了有如下操作:

 private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }

範例:觀察一個程序

public class ThreadDemo {

	public static void main(String[] main)throws Exception {
		new Thread(new MyThread(), "Thread-A").start();
		new Thread(new MyThread()).start();
		new Thread(new MyThread(), "Thread-B").start();
		System.out.println(Thread.currentThread().getName());
	}
}

通過此時代碼可以發現當使用了“thread.run()”直接在主方法之中調用線程類對象中的run()方法所獲得的線程對象的名字爲"main",所以可以得出一個結論:主方法也是一個線程。那麼現在問題來了,所有的線程都是在進程上的劃分,那麼進程在哪裏?每當使用java命令執行程序的時候就表示啓動了一個JVM的進程,一臺電腦上可以同時啓動若干個JVM進程,所以每個JVM進程都會有各自的線程。

在任何的開發之中,主線程可以創建若干個子線程,創建子線程的目的是可以將一些複雜邏輯或者比較耗時的邏輯交由子線程處理;
範例:子線程處理

public class ThreadDemo {

	public static void main(String[] main)throws Exception {
		System.out.println("**********[主程序啓動]*********");
		new Thread(()->{
			for(int i = 0; i < 100; i++)
				System.out.println("**********[子程序1啓動執行]*********");
		}).start() ;
		System.out.println("**********[主程序執行]*********");
		System.out.println("***********[Over]***********");
		
	}
}

主線程負責處理整體流程,而子線程負責處理耗時操作。

2 線程休眠

如果說現在希望某一個線程暫緩執行,那麼就可以使用休眠的處理,在Thread類之中定義的休眠方法如下:
(1)休眠:public static void sleep​(long millis) throws InterruptedException;
(2)休眠:public static void sleep​(long millis, int nanos) throws InterruptedException;
在進行休眠的時候有可能會產生中斷異常“InterruptedException”,中斷異常屬於Exception子類,所以證明該異常必須進行處理。
範例:觀察休眠處理

package cn.victor.demo;

class MyThread implements Runnable{

	@Override
	public void run() {
		for(int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "run: i = " + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	
	
}

public class ThreadDemo {

	public static void main(String[] main)throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt).start();
		new Thread(mt).start();
	}
}

休眠的主要特點是可以自動實現線程的喚醒,以繼續進行後續的處理。但是需要注意的是,如果現在你有多個線程對象,那麼休眠也是有先後順序的。
範例:產生多個線程對象進行休眠處理

package cn.victor.demo;

class MyThread implements Runnable{

	@Override
	public void run() {
		for(int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "run: i = " + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	
	
}

public class ThreadDemo {

	public static void main(String[] main)throws Exception {
		for(int i =0; i < 5; i++) {
			new Thread(()->{
				for(int j =0; j < 100; j++) {
					System.out.println(Thread.currentThread().getName() + "Thread run  " + j);
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}).start() ;
		}
	}
}

此時將產生五個線程對象,並且這五個線程對象執行的方法體是相同的。此時從程序執行的感覺上來講好像是若干個線程一起進行了休眠,而後一起進行了喚醒,但是實際上是有差別的。

3 線程中斷

在之前發現線程的休眠裏面提供有一箇中斷異常,實際上就證明線程的休眠是可以被打斷的,而這種打斷肯定是由其它線程完成的,在Thread類裏面提供有這種中斷執行的處理方法:
(1)判斷線程是否被中斷:public boolean isInterrupted()
(2)中斷線程執行:public void interrupt()`;
範例:觀察線程的中斷處理操作

public static void main(String[] main)throws Exception {
		Thread th = new Thread() {

			@Override
			public void run() {
				System.out.println("海燕學習太累了,休息會");
				try {
					Thread.sleep(10000);
					System.out.println("海燕休息好了,繼續學習");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					System.out.println("惡龍咆哮,嗷嗚嗷嗚!");
				}
			}
			
		} ;
		th.start();
		Thread.sleep(2000);
		if(!th.isInterrupted()) {
			System.out.println("當頭一摸");
			th.interrupt();
		}
		
	}

所有正在執行的線程都是可以被中斷的 ,中斷線程必須進行異常的處理。

4 線程強制運行

所謂的線程強制執行指的是當滿足於某些條件之後,某一個線程對象將可以一直獨佔資源,一直到該線程的程序執行結束。
範例:觀察一個沒有強制執行的程序

public static void main(String[] main)throws Exception {
		Thread th = Thread.currentThread();
		new Thread(()->{
			
			for(int i = 0; i < 100; i++) {
				System.out.println("小屁孩玩泥巴!");
			}
		}, "小屁孩進程").start();
		
		for(int i =0; i < 100; i++) {
			System.out.println("大人建房子!");
		}
	}

這個時候主線程和子線程都在交替執行,一直到執行完畢,但是如果現在希望主線程獨佔執行。那麼就可以利用Thread類中的方法。
(1)強制執行:public final void join() throws InterruptedException;
範例:多線程的強制執行

public static void main(String[] main)throws Exception {
		Thread th = Thread.currentThread();
		new Thread(()->{
			for(int i = 0; i < 100; i++) {
				if(i == 10) {
					try {
						th.join();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println("小屁孩玩泥巴!");
			}
		}, "小屁孩進程").start();
		
		for(int i =0; i < 100; i++) {
			System.out.println("大人建房子!");
		}
	}

在進行線程強制執行的時候一定要獲取強制執行線程對象之後纔可以執行join的調用。

5 線程禮讓

線程的禮讓指的是先將資源讓出去讓別的線程先執行。線程的禮讓可以使用Thread中提供的方法:
(1)禮讓:public static void yield();
範例:使用禮讓操作

public static void main(String[] main)throws Exception {
		new Thread(()->{
			for(int i = 0; i < 100; i++) {
				if(i% 3 == 0) {
					System.out.println(Thread.currentThread().getName() + "yield!");
					
					Thread.currentThread().yield();
				}
				System.out.println("小屁孩玩泥巴!");
			}
		}, "小屁孩進程").start();
		new Thread(()->{
			for(int i =0; i < 100; i++) {
				System.out.println("大人建房子!");
			}
		}, "大屁孩進程").start();
	}

禮讓執行的時候每一次調用yield()方法都只會禮讓一次當前的資源。

6 線程優先級

從理論上來講線程的優先級越高越有可能先執行(越有可能先搶佔到資源)。在Thread類裏面針對優先級的操作提供有如下的兩個處理方法:
(1)設置優先級:public final void setPriority​(int newPriority);
(2)獲取優先級:public final int getPriority();
在進行優先級定義的時候都是通過int型的數字來完成的,而對於此數字的選擇在Thread類裏面就定義有三個常量:
(1)最高優先級:public static final int MAX_PRIORITY;
(2)中等優先級:public static final int NORM_PRIORITY;
(3)最低優先級:public static final int MIN_PRIORITY;
範例:觀察優先級

class MyThread implements Runnable{

	@Override
	public void run() {
		for(int i = 0; i < 10; i++) {
			System.out.println(Thread.currentThread().getName() + "run: i = " + i);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	
	
}

public class ThreadDemo {

	public static void main(String[] main)throws Exception {
		Runnable mt = new MyThread();
		Thread threadA = new Thread(mt);
		Thread threadB = new Thread(mt);
		Thread threadC = new Thread(mt);
		threadA.setPriority(Thread.MAX_PRIORITY);
		threadB.setPriority(Thread.MIN_PRIORITY);
		threadC.setPriority(Thread.MIN_PRIORITY);
		threadA.start();
		threadB.start();
		threadC.start();
	}
}

主方法是一個主線程,那麼主線程的優先級呢?

public class ThreadDemo {

	public static void main(String[] main)throws Exception {
		Thread th = Thread.currentThread();
		Runnable mt = new MyThread();
		Thread threadA = new Thread(mt);
		System.out.println(threadA.getPriority());
		System.out.println(th.getPriority());
	}
}

主線程屬於中等優先級,而默認創建的線程也是中等優先級。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章