1. 程式人生 > >Thread三種實現&多執行緒操作同一物件的互斥同步以及多物件的同步&定時器Timer

Thread三種實現&多執行緒操作同一物件的互斥同步以及多物件的同步&定時器Timer

多執行緒

程序

  • 程序:(Process)是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位,是作業系統結構的基礎。在程序是程式的基本執行實體,在當代面向執行緒設計的計算機結構中,程序是執行緒的容器,程是程式的實體。

  • 多執行緒:是指從軟體或者硬體上實現多個執行緒併發執行的技術,是為了提高CPU等資源的使用率而採用的一種新技術。將一個執行活動-程序,拆分為多個小的執行片段,片段之間是共享資料而完成程序任務,進而提升整體處理效能。

  • Java程式執行

    • Java命令去啟動JVM,JVM會啟動一個程序,該程序會啟動一個主執行緒。
    • JVM的啟動是多執行緒的,因為它最低有兩個執行緒啟動了,主執行緒和垃圾回收執行緒。
  • 程序的實現方式:

    • 繼承Thread類.

      /*for example*/
      public final String getName()	//獲取執行緒的名稱。
      public final void setName(String 	//name):設定執行緒的名稱
      System.out.println(Thread.currentThread().getName());	//控制檯顯示當前指定物件名字。
      
      public class MyThread extends Thread {
      	public MyThread() {
      	}
      	
      	public MyThread(String name){
      		super(name);
      	}
      
      	@Override
      	public void run() {
      		for (int x = 0; x < 100; x++) {
      			System.out.println(getName() + ":" + x);
      		}
      	}
      }
      
      public static void main(String[] args) {
      		
      	/*method:the first...*/
      		MyThread myThread1 = new MyThread();
      		MyThread myThread2 = new MyThread();
      		
      		myThread1.setName("Tom");
      		myThread2.setName("Jack");
      		myThread1.start();
      		myThread2.start();
      		
      	/*method:the second...*/
      		 MyThread Thread1 = new MyThread("Tom");
      		 MyThread Thread2 = new MyThread("Jack");
      		 Thread1.start();
      		 Thread2.start();
      
    • 實現Runnable介面.

      public class MyRunnable implements Runnable {
      	@Override
      	public void run() {
      		for (int x = 0; x < 10; x++) {			
      			System.out.println(Thread.currentThread().getName() + ":" + x);
      		}
      	}
      
      }
      
      
      public class MyRunnable {
      	public static void main(String[] args) {	
      		MyRunnable my = new MyRunnable();
      
      	/*method:the first...*/		
      		Thread Thread1 = new Thread(my);
      		Thread Thread2 = new Thread(my);
      		Thread1.setName("Tom");
      		Thread2.setName("Jack");
      
      	/*method:the second...*/
      		Thread Thread1 = new Thread(my, "Tom");
      		Thread Thread2 = new Thread(my, "Jack");
      
      		Thread1.start();
      		Thread2.start();
      	}
      }
      
    • Callable&ExecutorService.

      /*for example*/		
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;		
      import java.util.concurrent.Callable;
      
      /*Callable:是帶泛型的介面,這裡指定的泛型其實是call()方法的返回值型別*/
      @SuppressWarnings("rawtypes")
      class MyCallable implements Callable {
      	/*Callable JDK1.5*/
      	@Override
      	public Object call() throws Exception {
      		for (int x = 0; x < 50; x++) {
      			System.out.println(Thread.currentThread().getName() + ":" + x);
      		}
      		return null;
      	}
      }
      
      public class CallableDemo {	
      	public static void main(String[] args) {
      		/*建立執行緒池物件*/
      		ExecutorService pool = Executors.newFixedThreadPool(2);
      
      		pool.submit(new MyCallable());
      		pool.submit(new MyCallable());
      	
      		pool.shutdown();
      	}
      }
      
      
  • 執行緒的排程和優先順序問題

    • 執行緒的排程:分時排程,時間片輪轉機制,而Java是採用搶佔式排程。
    • 獲取&設定執行緒優先順序:Java中執行緒執行的優先順序自高到底:10級->1級,預設5級;需要說明的是不是執行的級別越高就保證一定先執行該執行緒完該執行緒再執行其他低優先順序的執行緒,只是保證其具有很大的可能有優先順序。
  • 執行緒的控制

    • 休眠執行緒

      /*for example*/
      /*
      	public static void sleep(long millis)
       */
      import java.util.Date;
      
      public class ThreadSleep extends Thread {
      	@Override
      	public void run() {
      		for (int x = 0; x < 20; x++) {
      			System.out.println(getName() + ":" + x + ",Date:" + new Date());		
      			try {
      				Thread.sleep(1000);
      			} catch (InterruptedException e) {
      				e.printStackTrace();
      			}
      		}
      	}
      	
      	/* 解決直接重新命名執行緒名稱.*/
      	/*public ThreadSleep(String name){
      		super(name);
      	}*/
      }
      
      public class ThreadSleepDemo {
      	public static void main(String[] args) {
      		ThreadSleep Aa = new ThreadSleep();
      		ThreadSleep Bb = new ThreadSleep();
      		ThreadSleep Cc = new ThreadSleep();
      		
      		/*ThreadSleep Dd = new ThreadSleep("Smith");*/
      		Aa.setName("Tom");
      		Bb.setName("John");
      		Cc.setName("Jack");
      
      		Aa.start();
      		Bb.start();
      		Cc.start();
      	}
      }
      
    • 加入執行緒

      /*實現join功能*/
      package CompareTools;
      
      class sleepThread extends Thread {
      	@Override
      	public void run() {		
      		for (int i = 0; i < 10; ++i) {
      			try {
      				sleep(500);
      			} catch (InterruptedException e) {				
      				e.printStackTrace();
      			}
      			System.out.println(getName() + ":" + i);
      		}
      	}
      
      	public sleepThread() {
      	}
      
      	public sleepThread(String name) {
      		super(name);
      	}}
      
      public class TestFiles {
      	public static void main(String[] args) {
      		// TODO Auto-generated method stub
      		sleepThread spOne = new sleepThread("Tom");
      		sleepThread spTwo = new sleepThread("Jack");
      		sleepThread spThree = new sleepThread("Smith");	
      		spThree.start();
      		try {
      			spThree.join();
      		} catch (InterruptedException e) {
      			// TODO Auto-generated catch block
      			e.printStackTrace();
      		}		
      		spOne.start();
      		spTwo.start();		
      	}
      }
      /*Smith執行完成才繼續執行後面的,但若將spThree放到try後面不會有描述的效果。*/
      
    • 禮讓執行緒

      package CompareTools;
      
      class PriorityThread implements Runnable {
      	@Override
      	public void run() {
      		for (int i = 0; i < 10; ++i) {
      			
      			/* 實現Runnable無法使用Thread的getName函式. */			
      			System.out.println(Thread.currentThread().getName() + ":" + i);
      			
      			Thread.yield();	/*禮讓不代表一定是程式嚴格執行一次就對方執行.*/
      		}
      	}
      }
      
      public class TestFiles {
      	public static void main(String[] args) {
      		PriorityThread pt = new PriorityThread();
      		PriorityThread ptt = new PriorityThread();
      
      		Thread trr = new Thread(pt, "Jack");
      		/*Thread trr = new Thread(pt, "Tom")一樣執行看不出什麼問題.*/
      		Thread tr = new Thread(ptt, "Tom");
      
      		tr.setName("newName");
      		trr.setName("newNameName");
      
      		tr.start();
      		trr.start();
      	}
      }
      
    • 守護執行緒

      /*public final void setDaemon(boolean on):將該執行緒標記為守護執行緒或使用者執行緒。*/
      		當正在執行的執行緒都是守護執行緒時,Java 虛擬機器退出。
      
      /*for example*/
      
      td1.setDaemon(true);
      td2.setDaemon(true);
      
      td1.start();
      td2.start();
      System.out.println("Over!");
      
      result:--迴圈結構寫稍微大一些可以看到效果,迴圈到部分虛擬機器就退出。
      Over!
      Thread-1:0
      Thread-0:0
      Thread-1:1
      Thread-0:1
      Thread-1:2
      Thread-0:2
      Thread-1:3
      Thread-1:4
      Thread-1:5
      Thread-1:6
      Thread-0:3
      Thread-1:7
      Thread-1:8
      Thread-0:4
      Thread-1:9
      Thread-1:10
      ...
      
    • 優先順序設定

      package CompareTools;
      /*設定優先順序不能保證一定是是優先順序高的限制性,java中只能表示優先,但是不是先執行完高級別的再執行低級別.*/
      class PriorityThread implements Runnable {
      	@Override
      	public void run() {
      		for (int i = 0; i < 10; ++i) {
      			System.out.println(Thread.currentThread().getName() + ":" + i);
      			try {
      				Thread.sleep(100);
      			} catch (InterruptedException e) {
      				e.printStackTrace();
      			}
      		}
      	}
      }
      
      public class TestFiles {
      	public static void main(String[] args) {
      		PriorityThread pt = new PriorityThread();
      
      		Thread tr = new Thread(pt, "Jack");
      		Thread trr = new Thread(pt, "Tom");
      		Thread trrr = new Thread(pt, "Smith");
      
      		tr.setPriority(10);
      		trrr.setPriority(1);
      		tr.start();
      		trr.start();
      		trrr.start();
      
      	}
      }
      
    • 終止執行緒

      import java.util.Date;
      
      public class ThreadStop extends Thread {
      	@Override
      	public void run() {
      		System.out.println("開始執行:" + new Date());
      		/*睡眠10s*/		
      		try {
      			Thread.sleep(10000);
      		} catch (InterruptedException e) {			
      			System.out.println("執行緒被終止了!");
      		}
      		System.out.println("結束執行:" + new Date());
      	}
      }
      
      public class ThreadStopDemo {
      	public static void main(String[] args) {
      		ThreadStop ts = new ThreadStop();
      		ts.start();
      
      		/*3s不繼續執行,中斷.*/
      		try {
      			Thread.sleep(3000);
      			/*ts.stop();	直接終止.*/
      			ts.interrupt();		//執行緒被終止,結束執行還是可以顯示.
      		} catch (InterruptedException e) {
      			e.printStackTrace();
      		}
      	}
      }
      
    • 加入並檢視執行緒組

      public class ThreadGroupDemo {
      	public static void main(String[] args){
      		methodOne();		
      		methodTwo();
      	
      	}
      
      	private static void methodTwo() {
      		
      		ThreadGroup SetGroup = new ThreadGroup("NewGroupName");
      		MyRunnable SetThreadRunable = new MyRunnable();
      		
      		Thread t1 = new Thread(SetGroup, SetThreadRunable, "TheOne");
      		Thread t2 = new Thread(SetGroup, SetThreadRunable, "TheTwo");
      		
      		System.out.println(t1.getThreadGroup().getName());
      		System.out.println(t2.getThreadGroup().getName());		
      		
      		SetGroup.setDaemon(true);
      	}
      
      	private static void methodOne() {
      		MyRunnable SourceRunable = new MyRunnable();
      		Thread t1 = new Thread(SourceRunable, "FirstThread");
      		Thread t2 = new Thread(SourceRunable, "SecondThread");
      		
      		/*檢視預設情況下,執行緒所屬組別--預設是Main.*/
      	
      		ThreadGroup defaultTg1 = t1.getThreadGroup();
      		ThreadGroup defaultTg2 = t2.getThreadGroup();
      		
      		String nameOne = defaultTg1.getName();
      		String nameTwo = defaultTg2.getName();
      		System.out.println(nameOne);
      		System.out.println(nameTwo);
      		
      		System.out.println(Thread.currentThread().getThreadGroup().getName());
      	}
      }
      
  • 執行緒的生命週期
    新建->就緒->執行->阻塞->死亡。

  • 車站買票完整實現

    • 描述:買票用多執行緒實現,可以考慮適當的延遲,或者是為了保證程式的健壯性,保證問題不被掩蓋掉。問題有這兩種:一個是同一張車票賣了兩次,二是車票賣到了負數。

    • 如圖出錯:異常

    • 為了資料的安全性需要新增鎖進行實現而鎖有兩種:一種是Synchronized實現,一種是JDK1.4之後的lock實現。

      /*for example*/
      /*method:the first... */
      
      class SellTicket implements Runnable {	
      	private static int tickets = 100;	
      	private Object obj = new Object();
      	
      	@Override
      	public void run() {
      		while (true) {
      
      		/*在需要鎖的地方新增鎖物件,或者用obj替換SellTicket.class亦可!*/
      		/*this=SellTicket.class*/
      			synchronized (SellTicket.class) {
      				if (tickets > 0) {
      					try {
      						Thread.sleep(150);
      					} catch (InterruptedException e) {
      						e.printStackTrace();
      					}
      					System.out.println(Thread.currentThread().getName()
      							+ "printing" + (tickets--) + "th ticke!");
      }}}}}
      
      
      public class SellTicketDemo {
      	public static void main(String[] args) {
      		// 建立資源物件.
      		SellTicket st = new SellTicket();
      		
      		Thread thead1 = new Thread(st, "Windows-1:");
      		Thread thead2 = new Thread(st, "Windows-2:");
      		Thread thead3 = new Thread(st, "Windows-3:");
      		
      		thead1.start();
      		thead2.start();
      		thead3.start();
      	}
      }
      
      
      /*method:the second... */
      package CompareTools;
      
      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;
      
      class SellTicket implements Runnable {
      	private static int tickets = 100;
      	private Lock lock = new ReentrantLock();
      
      	@Override
      	public void run() {
      		while (true) {
      			try {
      				lock.lock();
      				if (tickets > 0) {
      					try {
      						Thread.sleep(100);
      					} catch (InterruptedException e) {
      						e.printStackTrace();
      					}
      					System.out.println(Thread.currentThread().getName()
      							+ "Printing" + (tickets--) + "th tickes!");
      				}
      			} finally {
      				lock.unlock();
      			}
      		}
      	}
      }
      
      public class TestFiles {
      	public static void main(String[] args) {
      		SellTicket sourceClass = new SellTicket();
      
      		Thread sta = new Thread(sourceClass, "Windows-1:");
      		Thread stb = new Thread(sourceClass, "Windows-2:");
      		Thread stc = new Thread(sourceClass, "Windows-3:");
      
      		sta.start();
      		stb.start();
      		stc.start();
      	}		
      }
      

關於使用繼承Thread&lock

  • 未曾達到預期結果,出錯程式碼在runable下執行正常,原因可能是實現介面的子類存在於Thread子類特有的差別,目前還無法明白具體原因,出錯例項如下:

    /*for example--出錯.*/
    --lock鎖搭配try...finally...出錯。
    package CompareTools;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    class SellTicket extends Thread {
    	private static int tickets = 100;
    	private Lock lock = new ReentrantLock();
    
    	public SellTicket() {
    	}
    
    	public SellTicket(String name) {
    		super(name);
    	}
    
    	@Override
    	public void run() {
    		while (true) {	
    			try{
    				lock.lock();
    				if (tickets > 0) {
    					try {
    						Thread.sleep(100);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(getName() + "Printing" + (tickets--)
    							+ "th tickes!");
    				}
    			}finally{
    				lock.unlock();}
    			}
    		}
    	}
    
    
    public class TestFiles {
    	public static void main(String[] args) {
    		SellTicket sta = new SellTicket("Windows-1:");
    		SellTicket stb = new SellTicket("Windows-2:");
    		SellTicket stc = new SellTicket("Windows-3:");
    
    		sta.start();
    		stb.start();
    		stc.start();
    	}
    
    }	
    
  • 多執行緒安全判定

    • 是否有多執行緒環境
    • 是否有共享資料
    • 是否有多條語句操作共享資料
  • 同步方法

    • 將方法有Synchronized修飾,可以同步方法。
    • Code eg:
      class SellTicket implements Runnable {
      
      	private static int tickets = 100;
      	private int x = 0;
      
      	@Override
      	public void run() {
      		while (true) {
      			if (x % 2 == 0) {
      				synchronized (SellTicket.class) {
      					if (tickets > 0) {
      						try {
      							Thread.sleep(100);
      						} catch (InterruptedException e) {
      							e.printStackTrace();
      						}
      						System.out.println(Thread.currentThread().getName()
      								+ "printing" + (tickets--) + "th ticket! ");
      					}
      				}
      			} else {
      				sellTicket();
      
      			}
      			x++;
      		}
      	}
      
      	private static synchronized void sellTicket() {
      		if (tickets > 0) {
      			try {
      				Thread.sleep(100);
      			} catch (InterruptedException e) {
      				e.printStackTrace();
      			}
      			System.out.println(Thread.currentThread().getName() + "printing"
      					+ (tickets--) + "th ticket! ");
      		}
      	}
      }
      
      public class SellTicketDemo {
      	public static void main(String[] args) {
      		SellTicket sourceClass = new SellTicket();
      
      		Thread window_1 = new Thread(sourceClass, "window_1:\t");
      		Thread window_2 = new Thread(sourceClass, "window_2:\t");
      		Thread window_3 = new Thread(sourceClass, "window_3:\t");
      
      		window_1.start();
      		window_2.start();
      		window_3.start();
      	}
      }
      
  • 同步的使用可以修改為對:要求執行緒嚴格遵守一個執行緒執行一次的要求,也可以利用經典的互斥問題,哲學家就餐問題和生產消費問題。

互斥&同步實現

  • 描述:問題的起源。

  • 首先是由於執行緒的不嚴格控制導致的生產消費的死鎖問題,也就是多個物件佔有其他物件所必需的資源,導致自己無法獲取資源,陷入無限等待的姿態。

    • 互斥條件:指程序對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個程序佔用。如果此時還有其它程序請求資源,則請求者只能等待,直至佔有資源的程序用畢釋放。

    • 請求和保持條件:指程序已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它程序佔有,此時請求程序阻塞,但又對自己已獲得的其它資源保持不放。

    • 不剝奪條件:指程序已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。

    • 環路等待條件:指在發生死鎖時,必然存在一個程序——資源的環形鏈,即程序集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1佔用的資源;P1正在等待P2佔用的資源,……,Pn正在等待已被P0佔用的資源。

  • 解除死鎖狀態

    • 死鎖預防:這是一種較簡單和直觀的事先預防的方法。方法是通過設定某些限制條件,去破壞產生死鎖的四個必要條件中的一個或者幾個,來預防發生死鎖。預防死鎖是一種較易實現的方法,已被廣泛使用。但是由於所施加的限制條件往往太嚴格,可能會導致系統資源利用率和系統吞吐量降低。

    • 死鎖避免:系統對程序發出的每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源;如果分配後系統可能發生死鎖,則不予分配,否則予以分配。這是一種保證系統不進入死鎖狀態的動態策略。

    • 死鎖檢測和解除:先檢測,這種方法並不須事先採取任何限制性措施,也不必檢查系統是否已經進入不安全區,此方法允許系統在執行過程中發生死鎖。但可通過系統所設定的檢測機構,及時地檢測出死鎖的發生,並精確地確定與死鎖有關的程序和資源。檢測方法包括定時檢測、效率低時檢測、程序等待時檢測等。

    • Code 同步互斥:

      /*
      Object類中提供的三個方法:
      	wait():等待
      	notify():喚醒單個執行緒
      	notifyAll():喚醒所有執行緒
      	為什麼不定義在Thread類中?
      			這些方法的呼叫必須通過鎖物件Lock呼叫,而我們使用的鎖物件可能是任意鎖物件.
      		所以,這些方法必須定義在Object類中是為了實現物件的通用性。
      */
      
      /* Tom-5.
       * Jack-6. 
       */
      
      /*該部分程式碼塊實現的是:多執行緒情況下,保證執行緒執行一步就暫停,而然另外執行緒執行*/
      package CompareTools;
      class Student {
      	String name;
      	int age;
      	boolean flag;
      }
      class GetThread implements Runnable {
      	private Student s;
      	public GetThread(Student s) {
      		this.s = s;
      	}
      	@Override
      	public void run() {
      		while (true) {
      			synchronized (s) {	/*鎖定區域性,而實際造成的結果是完全鎖定執行,防止干擾*/
      				if(!s.flag){	/*為true則獲取值,顯示在介面*/
      					try {
      						s.wait();	/*解鎖+等待...*/
      					} catch (InterruptedException e) {
      						e.printStackTrace();
      					}
      				}				
      				System.out.println(s.name + "---" + s.age);					
      				s.flag = false;		/*使用完成後就修改,保證SetThread執行.*/	
      				s.notify();	/*喚醒GetThread=喚醒...*/
      }}}}
      
      class SetThread implements Runnable {
      	private Student s;
      	private int x = 0;
      	public SetThread(Student s) {
      		this.s = s;
      	}
      	@Override
      	public void run() {
      		while (true) {
      			synchronized (s) {	/*鎖定區域性,而實際造成的結果是完全鎖定執行,防止干擾*/
      				if(s.flag){		/*為flase執行賦值操作...*/
      					try {
      						s.wait(); 	/*解鎖+等待...*/
      					} catch (InterruptedException e) {
      						e.printStackTrace();
      					}
      				}				
      				if (x % 2 == 0) {
      					s.name = "Five";
      					s.age = 5;
      				} else {
      					s.name = "Six";
      					s.age = 6;
      				}
      				x++; 			
      				s.flag = true;	/*使用完成後就修改,保證GetThread執行.*/	
      				s.notify(); 	/*喚醒GetThread=喚醒..*/
      }}}}
      public class TestFiles {
      	public static void main(String[] args) {	
      		Student s = new Student();		
      	
      		SetThread st = new SetThread(s);
      		GetThread gt = new GetThread(s);
      		
      		Thread t1 = new Thread(st);
      		Thread t2 = new Thread(gt);
      		
      		t1.start();
      		t2.start();
      	}
      }
      
  • 經典的互斥同步-生產消費問題

描述:假設消費者生產者使用一個容器,生產者將產品生產到容器中,消費者將容器中的產品拿出來消費。

程式進入後需要首先檢測訊號量,判斷是否容器存在產品,若不存在,生產者互斥佔有並且生產產品放至容器,然後退出互斥佔有狀態,關閉鎖。保證消費者可以獲取容器並且使用,消費者使用使用時設定互斥鎖鎖定使用,使用完成返回容器,放開互斥鎖。並設定訊號量,保證自己不佔有為空的容器,導致死鎖。

  • Code - 互斥同步

    /*for example*/
    
    上程式碼結構:
    	
    	- 設定物件簡單具體類,是為了使用共享boolean變數,和設定/獲取方法。
    	- 設定互斥設定名字 <=> 生產者互斥同步生產產品.
    	- 設定互斥獲取名字 <=> 消費者互斥同步消費產品.
    	- 主函式,呼叫兩個執行緒:互斥設定&互斥共享執行緒。
    
    	- 建立兩個物件,進行類似生產消費操作code。	
    package CompareTools;
    
    class Student {
    	String name;
    	int age;
    	boolean flag;
    }
    
    class GetThread implements Runnable {
    	private Student s;
    
    	public GetThread(Student s) {
    		this.s = s;
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			synchronized (s) { /* 鎖定區域性,而實際造成的結果是完全鎖定執行,防止干擾 */
    				if (!s.flag) { /* 為true則獲取值,顯示在介面 */
    					try {
    						s.wait(); /* 解鎖+等待... */
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    				System.out.println(Thread.currentThread().getName()+ s.name + "---" + s.age);
    				s.flag = false; /* 使用完成後就修改,保證SetThread執行. */
    				s.notify(); /* 喚醒GetThread=喚醒... */
    			}
    		}
    	}
    }
    
    class SetThread implements Runnable {
    	private Student s;
    	private int x = 0;
    
    	public SetThread(Student s) {
    		this.s = s;
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			synchronized (s) { /* 鎖定區域性,而實際造成的結果是完全鎖定執行,防止干擾 */
    				if (s.flag) { /* 為flase執行賦值操作... */
    					try {
    						s.wait(); /* 解鎖+等待... */
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    				if (x % 2 == 0) {
    					s.name = "Five";
    					s.age = 5;
    				} else {
    					s.name = "Six";
    					s.age = 6;
    				}
    				System.out.println(Thread.currentThread().getName());
    				x++;
    				s.flag = true; /* 使用完成後就修改,保證GetThread執行. */
    				s.notify(); /* 喚醒GetThread=喚醒.. */
    			}
    		}
    	}
    }
    
    public class TestFiles {
    	public static void main(String[] args) {
    		Student s = new Student();
    
    		SetThread st = new SetThread(s);
    		GetThread gt = new GetThread(s);
    
    		Thread t1 = new Thread(st, "st");
    		Thread t2 = new Thread(gt, "gt");
    
    		t1.start();
    		t2.start();
    
    		System.out.println("------this is a dividing line------");
    
    		Student ss = new Student();
    
    		SetThread stt = new SetThread(ss);
    
    		GetThread gtt = new GetThread(ss);
    
    		Thread t11 = new Thread(stt, "stt");
    		Thread t22 = new Thread(gtt, "gtt");
    
    		t11.start();
    		t22.start();
    
    	}
    }
    
  • 執行結果:

  • 執行結果一:resultOne

  • 執行結果二:resultTwo

  • 改進的生產者消費者Code

    /*for example*/
    /*Tips:新增生產消費過程,方面檢視邏輯,同時存在第二次執行可能存在3比2先走,只需要清理控制檯,等幾秒鐘再執行即可,因為Java沒有指標不能操作記憶體,而自動回收機制效率不高。*/
    
    package CompareTools;
    
    class Student {
    	String name = "Products";
    	/*flag判斷的是容器是否存在商品,存在true;不存在false.*/
    	boolean flag = false;
    }
    
    class GetThread implements Runnable {
    	private Student s;
    
    	public GetThread(Student s) {
    		this.s = s;
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			if (s.flag) { /*有成品則消費.*/
    				synchronized (s) { /* 鎖定區域性互斥消費,防止干擾 */
    					System.out.println(Thread.currentThread().getName()+"expensing "+
    							s.name);
    					s.flag = false; /* 使用完成後就修改,保證生產者執行. */
    					s.notify(); /* 喚醒GetThread=喚醒... */
    				}
    
    			}
    		}
    	}
    }
    
    class SetThread implements Runnable {
    	private Student s;
    	private int x = 0;
    
    	public SetThread(Student s) {
    		this.s = s;
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			if (!s.flag) { /*沒有產品則生產產品。*/
    				synchronized (s) { /* 鎖定區域性互斥生產,防止干擾 */
    					if (x % 2 == 0) {
    						s.name = "CellPhone-2";						
    					} else {
    						s.name = "Pad-3";
    					
    					}
    					System.out.println(Thread.currentThread().getName()+"Producting: "
    							+ s.name );// result:two
    					x++;
    					s.flag = true; /* 使用完成後就修改,保證消費者執行. */
    					s.notify(); /* 喚醒GetThread=喚醒...*/
    				}
    
    			}
    		}
    	}
    }
    
    public class TestFiles {
    	public static void main(String[] args) {
    		Student s = new Student();
    
    		SetThread st = new SetThread(s);
    		GetThread gt = new GetThread(s);
    
    		Thread t1 = new Thread(st, "ThreadOneSet: ");
    		Thread t2 = new Thread(gt, "ThreadOneGet: ");
    
    		t1.start();
    		t2.start();
    
    		System.out.println("------this is a dividing line------");
    
    		Student ss = new Student();
    
    		SetThread stt = new SetThread(ss);
    
    		GetThread gtt = new GetThread(ss);
    
    		Thread t11 = new Thread(stt, "ThreadTwoSet: ");
    		Thread t22 = new Thread(gtt, "ThreadTwoGet: ");
    
    		t11.start();
    		t22.start();
    
    	}
    }
    
    
  • 執行緒池

    • 執行緒池,工具類,所有函式均由static修飾。

    • 常用函式Code如下:

      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      
      class MyRunnable implements Runnable{
      	public void run() {
      		for (int x = 0; x < 100; x++) {
      			System.out.println(Thread.currentThread().getName() + ":" + x);
      		}}
      }
      
      public class ExecutorsDemo {
      	public static void main(String[] args) {
      		// 建立一個執行緒池物件,引數為執行緒個數。
      		// public static ExecutorService newFixedThreadPool(int nThreads)
      		ExecutorService pool = Executors.newFixedThreadPool(2);
      
      		// 可以執行Runnable物件或者Callable物件的執行緒.
      		pool.submit(new MyRunnable());
      		pool.submit(new MyRunnable());
      
      		/*結束執行緒池,否則不會死亡,等待下一物件來說使用.*/
      		pool.shutdown();
      	}
      }
      
  • Callable&executors

    • Code eg:
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;		
      import java.util.concurrent.Callable;
      
      /*Callable:是帶泛型的介面,這裡指定的泛型其實是call()方法的返回值型別*/
      @SuppressWarnings("rawtypes")
      class MyCallable implements Callable {
      	/*Callable JDK1.5*/
      	@Override
      	public Object call() throws Exception {
      		for (int x = 0; x < 50; x++) {
      			System.out.println(Thread.currentThread().getName() + ":" + x);
      		}
      		return null;
      	}
      }
      
      public class CallableDemo {	
      	public static void main(String[] args) {
      		/*建立執行緒池物件*/
      		ExecutorService pool = Executors.newFixedThreadPool(2);
      
      		pool.submit(new MyCallable());
      		pool.submit(new MyCallable());
      	
      		pool.shutdown();
      	}
      }
      
  • Callable&executors->sum.

    • Code eg:sum.
      import java.util.concurrent.Callable;
      import java.util.concurrent.ExecutionException;
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      import java.util.concurrent.Future;
      
      /*
       * Sum.
       */
      class MyCallable implements Callable<Integer> {
      
      	private int number;
      
      	public MyCallable(int number) {
      		this.number = number;
      	}
      
      	@Override
      	public Integer call() throws Exception {
      		int sum = 0;
      		for (int x = 1; x <= number; x++) {
      			sum += x;
      		}
      		return sum;
      	}
      }
      
      public class CallableDemo {
      	public static void main(String[] args) throws InterruptedException,
      			ExecutionException {
      
      		ExecutorService pool = Executors.newFixedThreadPool(2);
      
      		Future<Integer> result_01 = pool.submit(new MyCallable(50));
      		Future<Integer> result_02 = pool.submit(new MyCallable(100));
      
      		Integer sumOne = result_01.get();
      		Integer sumTwo = result_02.get();
      
      		System.out.println("Sum<50>: " + sumOne);
      		System.out.println("Sum<100>: " + sumTwo);
      
      		/* 結束執行緒池. */
      		pool.shutdown();
      	}
      }	
      
  • 匿名內部類&執行緒的使用

    • 匿名內部本質上是需要一個介面的實現類或者是抽象類的子類物件,實現潤able的內部類有如下幾種實現方法。
    • Code eg:
      /*for example*/
      
      /*
       * 匿名內部類的格式:
       * 		new 類名或者介面名() {
       * 			重寫方法;
       * 		};
       * 		本質:是該類或者介面的子類物件。
       */
      public class ThreadInner {
      	public static void main(String[] args) {
      		/*繼承Thread類來實現多執行緒*/
      		/*new Thread(){override Code block}.start();*/
      		new Thread() {
      			public void run() {
      				for (int x = 0; x < 100; x++) {
      					System.out.println(Thread.currentThread().getName() + ":"
      							+ x);
      				}
      			}
      		}.start();
      
      		/*實現Runnable介面來實現多執行緒*/
      		/*new Thread(override Code block){}.start();*/
      		new Thread(new Runnable() {
      			@Override
      			public void run() {
      				for (int x = 0; x < 100; x++) {
      					System.out.println(Thread.currentThread().getName() + ":"
      							+ x);
      				}
      			}
      		}) {
      		}.start();
      
      		/*更有難度的巢狀,本質上考驗到底執行哪一部分.*/
      		/*new Thread(new Runable()程式碼塊){抽象方法Runable程式碼塊}.start();-按照邏輯順序,走子類物件部分,也就是new Thread(){override Code block}.start();*/
      		new Thread(new Runnable() {
      			@Override
      			public void run() {
      				for (int x = 0; x < 100; x++) {
      					System.out.println("hello" + ":" + x);
      				}
      			}
      		}) {
      			public void run() {
      				for (int x = 0; x < 100; x++) {
      					System.out.println("world" + ":" + x);
      				}
      			}
      		}.start();
      	}
      }
      
  • Timer定時器

    • 提供一個類Timer實現定時執行操作的功能。
    • Code eg:資料夾刪除.
      import java.io.File;
      import java.text.ParseException;
      import java.text.SimpleDateFormat;
      import java.util.Date;
      import java.util.Timer;
      import java.util.TimerTask;
      
      class DeleteFolder extends TimerTask {
      
      	@Override
      	public void run() {
      		File srcFolder = new File("其他檔案");
      		deleteFolder(srcFolder);
      	}
      
      	/*遞迴刪除目錄*/
      	public void deleteFolder(File srcFolder) {
      		File[] fileArray = srcFolder.listFiles();
      		if (fileArray != null) {
      			for (File file : fileArray) {
      				if (file.isDirectory()) {
      					deleteFolder(file);
      				} else {
      					System.out.println(file.getName() + ":" + file.delete());
      				}
      			}
      			System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
      		}
      	}
      }
      
      public class TimerTest {
      	public static void main(String[] args) throws ParseException {
      		Timer t = new Timer();
      
      		String s = "10:05 2018/11/11"; 
      		SimpleDateFormat sdf = new SimpleDateFormat("HH:mm yyyy/MM/dd");
      		Date d = sdf.parse(s);
      
      		t.schedule(new DeleteFolder(), d);
      	}
      }