1. 程式人生 > >多執行緒的方法總結

多執行緒的方法總結

/*
1.多執行緒的實現方法
	A:通過繼承自Thread類
		a.把要使用多執行緒實現的程式碼封裝在一個繼承Thread的類中。
		b.重寫run方法,把程式碼放在run方法中。
		c.建立該類的例項,使用start方法開啟執行緒。
		匿名內部類的實現方法:
			new Thread(){
				public void run(){
					System.out.println("這裡寫要實現功能的程式碼");
				}
			}.start();
	B:通過實現Runnable介面
		a.把要使用多執行緒實現的功能封裝在一個實現了Runnable介面的類中。
		b.重寫run方法,把功能寫在run方法中。
		c.建立該類的物件。
		d.以該物件為引數傳遞給Thread,建立Thread物件。呼叫Thread物件的start開啟執行緒。
		匿名內部類的實現方法:
			new Thread(new Runnable(){
				public void run(){
					System.out.println("這裡寫要實現功能的程式碼");
				}
			}){}.start();
	注:如果使用匿名內部類同時存在實現Runnable介面和Thread子類物件,那麼會執行
	子類物件的run方法。
	C:通過執行緒池實現
		a.寫一個實現Runnable介面或實現了Callable介面的實現類
		b.把要用多執行緒實現的功能寫在run方法或call方法中。
		c.建立一個執行緒池——使用Executors類的靜態方法
			public static ExecutorServer newFixedThreadPool(int nThreads);
		d.使用執行緒池的submit方法開啟執行緒
			注:
				使用Runnable介面實現時沒有返回值,但是Callbale的call方法是有返回值的,
				該返回值其實就是call方法的返回值。
				Future<?> submit(Runnable task);
				<T> Future<T> submit(Callable<T> task);
	注:使用執行緒池時,執行緒執行完畢後執行緒池不會關閉,如果需要關閉需要使用shutdown方法
	而通過繼承和實現來開啟的執行緒,當執行緒執行完畢後就自動關閉了。
2.執行緒的常用方法
	public final void setName(String name)		命名
	public final void getName()						獲取名
	public final void setPriority(int newPriority)	設定優先順序
	public final int getPriority()						獲取優先順序
	public finlal void join()								執行緒加入(等待該執行緒終止後再執行其他執行緒)
	public static void yield()							執行緒禮讓
3.特殊方法:
	通過Thread的靜態方法獲取當前正在執行的執行緒物件
	pulbic static Thread currentThread();
	
	守護執行緒,當執行的執行緒都是守護執行緒時,java虛擬機器會退出
	該方法必須在啟用執行緒前呼叫才會生效。
	public final void setDaemon(boolean on);
4.同步機制解決執行緒安全問題
	A:安全問題產生的原因:
		a.有多執行緒環境
		b.有共享資料
		c.有多條語句操作共享資料
	B:同步程式碼塊:
		把有執行緒安全問題的程式碼寫在同步程式碼塊中
			synchronized(鎖物件){
				需要同步的程式碼
			}
		同步程式碼塊的鎖物件可以是任意的物件,但是必須是同一個物件!
		synchronized的位置問題:
			絕對不能加到run方法上,一旦加到了run方法上就變成了單執行緒了。
			哪些程式碼對共享資料操作進加到哪些程式碼上,但此例中不能使用while(ticket>0),因為
			此程式碼即是條件判斷又是對共享資料的操作,一旦使用這個,則必須放到synchronized中,
			但此時也就相當於是加到了run方法上了。
	C:同步方法:
		直接用synchronized關鍵字修飾方法名
		此時的鎖物件問題:
			非靜態方法:鎖物件是this
			靜態方法:鎖物件是this.getCalss()
	D:建立鎖物件:
		Lock lock = new ReenTrantLock();
		lock.lock();
			把需要同步的程式碼,放在中間。
		lock.unlock();
		為了保證鎖一定會被釋放,可以使用try{...}finally{...}結構,
		把釋放鎖的操作放到finally中完成。
5.等待喚醒機制解決多執行緒的通訊問題
	不同執行緒對共享資料操作,至少一個生產者和一個消費者。
	等待喚醒機制是由鎖物件來執行的,而同步程式碼塊的鎖物件可以是任意物件
	所以wait(),notify(),notifyAll()等方法都定義在Object類中。
	實現:
		定義一個標記標籤,來追蹤狀態——是否有資訊
		在設定資訊時先做判斷,
			如果有資訊則等待消費者來取資訊s.wait();
			如果沒有資訊則設定資訊,然後更改標籤,並喚醒消費端的等待執行緒s.notyfy();
		同理,在取資訊時也要先做判斷
			如果有資訊則取出,然後更改標籤,並喚醒服務端的等待執行緒s.notify();
			如果沒有資訊,則等待生產者提供資訊s.wait();
6.常見問題
	sleep()和wait()方法的區別
		sleep():必須指時間;不釋放鎖。
		wait():可以不指定時間,也可以指定時間;釋放鎖。
	同步的弊端:
		效率較低;
		容易產生死鎖問題;
	死鎖問題:
		死鎖的產生原因:
			兩個或兩個以上的執行緒(必須是兩個以上的鎖物件)在爭奪資源的過程中,發生的一種相互等待的現象。
			即:我有一個鎖,我拿著我的鎖去訪問你的資源,同時你也有一個鎖,你拿著你的鎖來訪問我的
			資源,我們倆同時訪問物件的資源,但又沒有釋放自己的鎖,所以出現相互等待。
		程式碼演示:同步中巢狀同步而鎖卻不同
			public class MyLock {
				// 建立兩把鎖物件
				public static final Object objA = new Object();
				public static final Object objB = new Object();
			}
			public class DieLock extends Thread {
				private boolean flag;
				public DieLock(boolean flag) {
					this.flag = flag;
				}
				@Override
				public void run() {
					if (flag) {
						synchronized (MyLock.objA) {
							System.out.println("if objA");
							synchronized (MyLock.objB) {
								System.out.println("if objB");
							}
						}
					} else {
						synchronized (MyLock.objB) {
							System.out.println("else objB");
							synchronized (MyLock.objA) {
								System.out.println("else objA");
							}
						}
					}
				}
			}
			public class DieLockDemo {
				public static void main(String[] args) {
					DieLock dl1 = new DieLock(true);
					DieLock dl2 = new DieLock(false);

					dl1.start();
					dl2.start();
				}
			}
7.特殊的執行緒類TimerTask
	與Timer類配合使用來執行定時任務
	可以讓我們在指定的時間做某件事情,還可以重複的做某件事情
	Timer——定時——的常用方法
		public Timer();	構造方法
		public void schedule(TimerTask task,long delay);	delay毫秒後執行task任務
		public void schedele(TimerTask task,long delay,long period);
		delay毫秒後執行task任務,然後每個period毫秒再執行一次。
		public void schedule(TimerTask task, Date time)		在指定的時間執行task任務
		public void schedule(TimerTask task, Date firstTime, long period)
		在指定的時間執行task任務,然後每隔period毫秒再執行一次
		public void cancel();		取消任務
	TimerTask——定時任務——是一個抽象的執行緒類,把任務寫在run方法中
	例項:在指定的時間刪除我們的指定目錄
		class DeleteFolder extends TimerTask {
			@Override
			public void run() {
				File srcFolder = new File("demo");
				deleteFolder(srcFolder);
			}
		}
		public class TimerTest {
			public static void main(String[] args) throws ParseException {
				Timer t = new Timer();
				String s = "2014-11-27 15:45:00";
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				Date d = sdf.parse(s);
				t.schedule(new DeleteFolder(), d);
			}
		}
*/