00 04Java高級之多線程深入話題

1 優雅的停止線程

在多線程的操作之中如果要啓動多線程肯定使用的是Thread類中的start()方法,而如果對於多線程需要進行停止處理,Thread類原本提供有stop()方法,但是對於這些方法從JDK1.2版本開始就已經將其廢除了,而且一直到現在也不再建議出現在你的代碼之中,而除了stop()方法之外,還有幾個方法也被禁用了:
(1)停止多線程:public final void stop()
(2)銷燬多線程:public void destroy()
(3)掛起線程:public final void suspend()、暫停執行;
(4)恢復掛起的線程執行:public final void resume()
之所以廢除掉這些方法,主要的原因是因爲這些方法有可能導致線程的死鎖,所以JDK 1.2開始就不建議使用了。如果這個時候要想實現線程的停止就需要通過一種柔和的方式來進行。
範例:實現線程柔和的停止

package cn.victor.demo;

public class ThreadDemo {
	public static boolean flag = true;

	public static void main(String[] args) throws InterruptedException {
		new Thread(()->{
			long num = 0;
			while(flag) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "run  num:" + num++);
			}
		}).start();
		
		Thread.sleep(200);
		flag = false;
		
	}
}


萬一現在有其他線程去控制這個flag的內容,那麼這個時候對於線程的停止也不是說停就立刻停止的,而是會在執行中判斷flag的內容來完成。

2 後臺守護線程

現在假設有一個人且這個人有一個保鏢,那麼這個保鏢一定是在這個人活着的時候進行守護,那麼如果這個往生了,那麼保鏢就沒用了。所以在多線程裏面可以進行守護線程的定義,也就是說如果現在主線程的程序或者其他的線程還在執行的時候,那麼守護線程將一直存在,並且運行在後臺狀態。

在Thread類裏面提供有如下的守護線程的操作方法:
(1)設置守護線程:public final void setDaemon​(boolean on)
(2)判斷是否爲守護線程:public final boolean isDaemon()
範例:使用守護線程

package cn.victor.demo;

public class ThreadDemo {
	public static boolean flag = true;

	public static void main(String[] args) throws InterruptedException {
		Thread user = new Thread(()->{
			long num = 0;
			while(flag && num < 10) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "run  num:" + num++);
			}
		}, "用戶線程");
		Thread daemon = new Thread(()->{
			long num = 0;
			while(flag) {
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "run  num:" + num++);
			}
		},"守護線程");
		daemon.setDaemon(true);  //設置爲守護線程
		user.start();
		daemon.start();
//		Thread.sleep(200);
		
	}
}


可以發現所有的守護線程都是圍繞在用戶線程周圍,如果程序執行完畢了,守護線程也就消失了,在整個JVM裏面,最大的守護線程就是GC線程。

程序執行中GC線程會一直存在,如果程序執行完畢,GC線程也將消失。

3 volatile關鍵字

在多線程定義之中,volatile關鍵字主要是在屬性的定義上使用的,表示此屬性爲直接數據操作,而不進行副本的拷貝處理,這樣的話在一些書上就將其錯誤的理解爲同步屬性了。

在正常進行變量處理的時候往往會經歷如下的幾個步驟:
(1)獲取變量原有的數據內容副本;
(2)利用副本爲變量進行數學計算;
(3)將計算後的變量,保存到原始空間之中。
而如果一個屬性上追加了volatile關鍵字,表示的就是不使用副本,而是直接操作原始變量,相當於節約了:拷貝副本,重新保存的步驟。

package cn.victor.demo;

class MyThread implements Runnable{
	private volatile int tickets = 5;
	
	@Override
	public void run() {
		synchronized(this) {
			while(this.tickets > 0) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "sale ticket " + this.tickets--);
			}
		}
	}
}

public class ThreadDemo {

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


面試題:情節是volatile與synchronized的區別?
(1)volatile主要在屬性上使用,而synchronized是在代碼塊與方法上使用的;
(2)volatile無法描述同步的處理,它只是一種直接內存的處理,避免了副本的操作,而synchronized是實現同步的。

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