Java張孝祥視頻 學習筆記 多線程

/*************************************************************************************/
此博客主要是在觀看張孝祥老師的教學視頻的過程中,自己所做的學習筆記,在此以博客的形式分享出來,方便大家學習,建議大家觀看視頻,以此筆記作爲回顧資料。
參考資料
傳智播客_張孝祥_Java多線程與併發庫高級應用視頻教程下載 視頻下載
/*******************01張孝祥傳統線程技術回顧************************/

創建線程的兩種方式:
1,創建Thread的子類,重寫run方法
2,給Thread類傳入Runnable接口

兩種方式的區別:
第二種方式可以實現數據共享,而且更傾向於面向對象的編程思想。一般都是採用第二種方式。

new Thread().start();
調用了start方法後,就會運行Thread類的run方法,如下
public void run(){
    if(target!=null){
       targe.run();
    }
}
如果target爲空,就什麼也不做



new Thread(
        new Runnable(){
             public void run() { //1
              
       }
  ){
       public void run() { //2
       
}.start();

執行的是2run方法
執行的步驟:
先運行子類的run方法,如果子類沒有重寫run方法,就去運行父類的run方法,上述代碼中子類重寫了run方法,所以就不會運行Runnable中的run方法。

/*******************02張孝祥傳統定時器技術回顧************************/
 1秒後,炸一次
 new Timer().schedule(new TimerTask() {
   
       @Override
       public void run() {
            System.out.println("bombing!");
       }
  }, 1000);
每隔兩秒炸一次<一方式>
new Timer().schedule(new TimerTask() {
   
       @Override
       public void run() {
            System.out.println("bombing!");
       }
}, 1000,2000);

 每隔兩秒鐘炸一次 <二方式>
 new Timer().schedule(new MyTimerTask(), 2000);

 class MyTimerTask extends TimerTask{
   
   @Override
   public void run() {
         System.out.println("bombing!");
        new Timer().schedule(new MyTimerTask(),2000); 
    }
  }
注意:每個TimerTask()只能運行一次
先隔一秒炸一次,再隔兩秒鐘炸一次,再擱一秒鐘炸一次,。。。。
private static int count =0;
new Timer().schedule(new MyTimerTask(), 1000);
class MyTimerTask extends TimerTask{
  
   @Override
   public void run() {
         count = (count+1)%2;
        System.out.println("bombing!");
        new Timer().schedule(new TimerTask(),1000+count*1000); 
    }
}

/*******************03張孝祥傳統線程互斥技術************************/

在靜態方法中,不能new內部類的實例對象
原因:
內部類,可以訪問外部類的成員變量,調用靜態方法的時候,沒有創建對象,此時沒有可以訪問的成員變量,所以會報錯。

回顧需要重新看視頻 

/*******************04張孝祥傳統線程同步通信技術************************/
回顧需要重新看視頻
/*******************05張孝祥線程範圍內變量的概念************************/
線程內部共享數據,線程間數據獨立

package cn.itcast.heima2;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class ThreadScopeShareData {
 
 private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
 public static void main(String[] args) {
      for(int i=0;i<2;i++){
           new Thread(new Runnable(){
           @Override
            public void run() {
                 int data = new Random().nextInt();
                 System.out.println(Thread.currentThread().getName() + " has put data :" + data); 
                 threadData.put(Thread.currentThread(), data);
                 new A().get();
                 new B().get();
            }
       }).start();
   }
 } 
 
 static class A{
      public void get(){
           int data = threadData.get(Thread.currentThread());
           System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data);
      }
 }
 
 static class B{
      public void get(){
      int data = threadData.get(Thread.currentThread());
      System.out.println("B from " + Thread.currentThread().getName()+ " get data :" + data);
    }
 }
}
/*******************06張孝祥ThreadLocal類及其應用技巧************************/

ThreadLocal類,實現了線程內部共享數據,線程間數據獨立,比05節視頻中的更加簡化方便

《1》
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


public class ThreadLocalTest {

 
     public static void main(String[] args) {
          new ThreadLocalTest().init();
     }
   //init
     private void init(){
          for(int i =0;i<2;i++){
               new Thread(new Runnable() {
   
                    public void run() {
     
                         int data = new Random().nextInt();
                         Person.getThreadInstance().setName(Thread.currentThread().getName()); 
                         Person.getThreadInstance().setAge(data);
                         new A().get(); 
                         new B().get();
                } 
           }).start();
        }
    } 
 //A
 class A {
      Person person = Person.getThreadInstance();
      public void get(){
           System.out.println("A:-"+Thread.currentThread().getName()+":name:"+person.getName()+":age:"+person.getAge());
         }
 }
 //B
 class B {
      Person person = Person.getThreadInstance();
      public void get(){
           System.out.println("B:-"+Thread.currentThread().getName()+":name:"+person.getName()+":age:"+person.getAge());
      }
}
 //Person   將跟線程相關的綁定,放在共享的數據類的內部實現
     static class Person{
          private static ThreadLocal<Person>  threadLocal = new ThreadLocal<ThreadLocalTest.Person>(); 
 
          private Person(){
   
          }
 
         public static Person  getThreadInstance(){
               Person person = threadLocal.get();
               if(person==null){
                    person = new Person();
                    threadLocal.set(person);
               }
               return person;.
         }
   
          private String name;
          private int age;
 
          public String getName() {
               return name;
          }
          public void setName(String name) {
                this.name = name;
          }
          public int getAge() {
               return age;
          }
          public void setAge(int age) {
               this.age = age;
          }
 
    } 
 
}


《2》
import java.util.HashMap;
import java.util.Map;
import java.util.Random;


public class ThreadLocalTest {


     public static final ThreadLocal<Person>  threadlocal = new  ThreadLocal(){

              @Override
              protected Object initialValue() {
   
                   return new Person();
              }
       
    };
 
     public static void main(String[] args) {
          new ThreadLocalTest().init();
     }
  
     private void init(){
          for(int i =0;i<2;i++){
               new Thread(new Runnable() {
   
                    public void run() {
     
                         int data = new Random().nextInt();
                         threadlocal.get().setName(Thread.currentThread().getName());
                         threadlocal.get().setAge(data);
                         new A().get();
                         new B().get();
                }
           }).start();
        }
    }
     //A
     class A {
          Person person = threadlocal.get();
          public void get(){
               System.out.println("A:-"+Thread.currentThread().getName()+":name:"+person.getName()+":age:"+person.getAge());
             }
     }
   //B
    class B {
       Person person = threadlocal.get();
       public void get(){
           System.out.println("B:-"+Thread.currentThread().getName()+":name:"+person.getName()+":age:"+person.getAge());
        }
    }
      //Person  
     static class Person{
       
          public Person(){ 
   
          }
 
          private String name; 
          private int age;
 
          public String getName() {
               return name;
          }
          public void setName(String name) {
                this.name = name;
          }
          public int getAge() {
               return age;
          }
          public void setAge(int age) {
               this.age = age;
          }
 
    }
 
}

/************07張孝祥多個線程之間共享數據的方式的討論**************/
如果每個線程執行的代碼相同,可以使用同一個Runnable對象,這個Runnable對象中有那個共享數據,例如,買票系統就可以這麼做。

如果每個線程執行的代碼不同,這時候需要用不同的Runnable對象,有如下兩種方式來實現這些Runnable對象之間的數據共享:

第一種: 將共享數據封裝在另外一個對象中,然後將這個對象逐一傳遞給各個Runnable對象。每個線程對共享數據的操作方法也分配到那個對象身上去完成,這樣容易實現針對該數據進行的各個操作的互斥和通信。 

第二種:將這些Runnable對象作爲某一個類中的內部類,共享數據作爲這個外部類中的成員變量,每個線程對共享數據的操作方法也分配給外部類,以便實現對共享數據進行的各個操作的互斥和通信,作爲內部類的各個Runnable對象調用外部類的這些方法。

上面兩種方式的組合:將共享數據封裝在另外一個對象中,每個線程對共享數據的操作方法也分配到那個對象身上去完成,對象作爲這個外部類中的成員變量或方法中的局部變量,每個線程Runnable對象作爲外部類中的成員內部類或局部內部類。

總之,要同步互斥的幾段代碼最好是分別放在幾個獨立的方法中,這些方法再放在同一個類中,這樣比較容易實現它們之間的同步互斥和通信。 
極端且簡單的方式,即在任意一個類中定義一個static的變量,這將被所有線程共享。

設計四個線程,其中兩個線程每次對j加一,另外兩個線程每次對j減一

第一種示例代碼
 
public class MultiThreadShareData { 
  private static ShareData shareData = new ShareData();
 
  public static void main(String[] args) {
      MyRunnable1 runNable1 = new MyRunnable1(shareData);
      MyRunnable2 runNable2 = new MyRunnable2(shareData);
      new Thread(runNable1).start();
      new Thread(runNable2).start();
  }
class ShareData{
       private int j =0; 
      public ShareData(){ 
      
     public void increment(){
          j++;
     }
     public void decrement(){
          j--;
     }
}
class MyRunnable1 implements Runnable{
     private ShareData shareData;
     public MyRunnable1(ShareData shareData){
          this.shareData = shareData;
     }
     public void run() {
          this.shareData.increment();
     }
class MyRunnable2 implements Runnable{
    private ShareData shareData;
    public MyRunnable2(ShareData shareData){
          this.shareData = shareData;
     }
    public void run() {
          this.shareData.decrement();
     }
或者
public class MultiThreadShareData { 
  
 
  public static void main(String[] args) {

      MultiThreadShareData multiThreadShareData = new MultiThreadShareData();

      ShareData shareData = multiThreadShareData.new ShareData(); 

      MyRunnable1 runNable1 = multiThreadShareData.new MyRunnable1(shareData);
      MyRunnable2 runNable2 = multiThreadShareData.new MyRunnable2(shareData);
      new Thread(runNable1).start();
      new Thread(runNable2).start();
  }
  
  
class ShareData{
       private int j =0; 
      public ShareData(){ 
      
     public void increment(){
          j++;
     }
     public void decrement(){
          j--;
     }
}
class MyRunnable1 implements Runnable{
     private ShareData shareData;
     public MyRunnable1(ShareData shareData){
          this.shareData = shareData;
     }
     public void run() {
          this.shareData.increment();
     }
class MyRunnable2 implements Runnable{
    private ShareData shareData;
    public MyRunnable2(ShareData shareData){
          this.shareData = shareData;
     }
    public void run() {
          this.shareData.decrement();
     }

  

第二種示例代碼


public class MultiThreadShareData {

     public static void main(String[] args) { 
         final ShareData shareData = new ShareData(); 
        
        new Thread(new Runnable() { 
            public void run() { 
                    shareData.increment();
             }
        }).start();
          
        new Thread(new Runnable() {
           public void run() { 
                 shareData.decrement();
            }
       }).start();
 }
 
 
}

class ShareData{
     private int j =0; 
     public ShareData(){ 
      
     public void increment(){
          j++;
     }
     public void decrement(){
          j--;
     }
}

/********************08張孝祥Java5原子性操作類的應用************************/

/********************09張孝祥Java5線程並法庫的應用**************************/

線程池的概念與Executors類的應用
創建固定大小的線程池
創建緩存線程池
創建單一線程池(如何實現線程死亡後重新啓動
關閉線程池 
shutdown與shutdownNow的比較
用線程池啓動定時器 
調用ScheduledExecutorService的schedule方法,返回的ScheduleFuture對象可以取消任務。支持間隔重複任務的定時方式,不直接支持絕對定時方式,需要轉換成相對時間方式。 
 

創建一個固定線程數量的線程池,內有3個線程,分配給了10個任務,3個線程執行這10個任務,當一個線程執行完一個任務之後,再去執行另一個任務,直到所有的任務執行完畢,但線程池中線程不會銷燬。
    ExecutorService executorService = Executors.newFixedThreadPool(3);
       for(int i=1;i<=10;i++){
            final int taskId = i;
            executorService.execute(new Runnable() {
                 public void run() {
                      for(int j=1;j<=10;j++){
                           System.out.println(Thread.currentThread().getName()+"----"+j+"次"+"execute task"+taskId);
                      }
                 }
            });
    }

創建一個緩存線程池,緩存線程池中線程的數量是不固定的,動態變化,剛開始有3個任務,就只有3個線程,後來又來了6個任務,那就又增加了6個線程,任務執行完後,超時一段時間,多餘線程銷燬。
   ExecutorService executorService = Executors.newCachedThreadPool();
       for(int i=1;i<=10;i++){
            final int taskId = i;
            executorService.execute(new Runnable() {
                 public void run() {
                      for(int j=1;j<=10;j++){
                           System.out.println(Thread.currentThread().getName()+"----"+j+"次"+"execute task"+taskId);
                      }
                 }
            });
   }
executorService.shutdown();        //當所有線程都空閒的時候,殺死線程,終止程序。
executorService.shutdownNow();//不管線程中的任務有沒有執行完,都殺死線程。

創建一個只含有一個線程的線程池,該線程池只含有一個線程,當線程池裏的線程被銷燬後,線程池又會創建一個線程,替代原來的線程 
ExecutorService executorService = Executors.newSingleThreadExecutor();
       for(int i=1;i<=10;i++){
            final int taskId = i;
            executorService.execute(new Runnable() {
                 public void run() {
                      for(int j=1;j<=10;j++){
                           System.out.println(Thread.currentThread().getName()+"----"+j+"次"+"execute task"+taskId);
                      }
                 }
            });
   }

創建一個調度線程池,內含有3個線程,實現10秒定時執行功能
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
       
scheduledExecutorService.schedule(new Runnable() {
   public void run() {
     System.out.println("bomb!!!");
    }
   },10, TimeUnit.SECONDS);

創建一個調度線程池,內含有3個線程,實現10秒定時執後,以後每隔2秒執行一次的功能。
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
   
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
   
    public void run() {
      System.out.println("bomb!!!");
    }
   },10, 2, TimeUnit.SECONDS);

 
/********************10張孝祥Callable與Future的應用**************************/
Future取得的結果類型和Callable返回的結果類型必須一致,這是通過泛型來實現的。

Callable要採用ExecutorSevice的submit方法提交,返回的future對象可以取消任務。

 
 System.out.println("主線程::::"+Thread.currentThread().getName());
  ExecutorService executorService = Executors.newSingleThreadExecutor();
  Future future = executorService.submit(new Callable() {
       public Object call() throws Exception {
            Thread.sleep(2000);
            return Thread.currentThread().getName();
           }
  }); 
  String string = null;
  try {
       System.out.println("等待開始");
       string = (String) future.get();//沒有結果會一直等待,知道有結果爲止
    //string = (String) future.get(10, TimeUnit.SECONDS);//等待10s,沒有有結果報異常
       System.out.println("等待結束");
  } catch (Exception e) {
       e.printStackTrace();
  }
  System.out.println("Callable線程::::"+string);

CompletionService用於提交一組Callable任務,其take方法返回已完成的一個Callable任務對應的Future對象。
好比我同時種了幾塊地的麥子,然後就等待收割。收割時,則是那塊先成熟了,則先去收割哪塊麥子。

  
    ExecutorService executorService = Executors.newFixedThreadPool(10);
    CompletionService completionService = new ExecutorCompletionService(executorService);
    for(int i=1;i<=10;i++){
           final int taskId = i;
           completionService.submit(new Callable() {
               public Object call() throws Exception { 
                     Thread.sleep(new Random().nextInt(5000)); 
                     return "執行完的任務的ID::::"+taskId;
                }
            });
      }
 
  for(int i=1;i<=10;i++){
     try { 
        String string = (String) completionService.take().get();
        System.out.println(string);
    } catch (Exception e) {
        e.printStackTrace();
    }
 }
/********************11張孝祥_java5的線程鎖技術**************************/
Lock比傳統線程模型中的synchronized方式更加面向對象,與生活中的鎖類似,鎖本身也應該是一個對象。兩個線程執行的代碼片段要實現同步互斥的效果,它們必須用同一個Lock對象。

public static void main(String[] args) {
   
      new LockTest().action();
 
 }
  
 private void action(){
 
      final Outputer outputer = new Outputer();
 
      new Thread(new Runnable() {
           public void run() { 
                for(int i=0;i<10;i++){ 
                     outputer.output("zhangxiaoxiang\n");
                }
           }
     }).start();
 
  new Thread(new Runnable() {
       public void run() { 
            for(int i=0;i<10;i++){
                 outputer.output("lihuoming\n");
            }
       }
     }).start();
 
private class Outputer{
      private Lock lock = null;
      public Outputer(){
           lock = new ReentrantLock();
      }
      public void output(String name){
   
           lock.lock();
           try{
                for(int i = 0;i<name.length();i++){
                     System.out.print(name.charAt(i));
            };
           }finally{
                lock.unlock();
           }
   
      }
}
/********************12張孝祥java5讀寫鎖技術的妙用**************************/
讀寫鎖:分爲讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,這是由jvm自己控制的,你只要上好相應的鎖即可。如果你的代碼只讀數據,可以很多人同時讀,但不能同時寫,那就上讀鎖;如果你的代碼修改數據,只能有一個人在寫,且不能同時讀取,那就上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖!

package cn.itcast.heima2; 
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockTest {
 public static void main(String[] args) {
      final Queue3 q3 = new Queue3();
      for(int i=0;i<3;i++)
      {
           new Thread(){
                public void run(){
                     while(true){ 
                          q3.get();
                }
             } }.start(); 
           new Thread(){
                public void run(){
                        while(true){
                              q3.put(new Random().nextInt(10000));
                         }
                }
           }.start(); 
       }
 
    }
class Queue3{
     private Object data = null;//共享數據,只能有一個線程能寫該數據,但可以有多個線程同時讀該數據。
     ReadWriteLock rwl = new ReentrantReadWriteLock();
     public void get(){
              rwl.readLock().lock();
              try {
                   System.out.println(Thread.currentThread().getName() + " be ready to read data!");
                   Thread.sleep((long)(Math.random()*1000));
                   System.out.println(Thread.currentThread().getName() + "have read data :" + data);
              } catch (InterruptedException e) {
                   e.printStackTrace();
              }finally{
                  rwl.readLock().unlock();
              }
    }
 
   public void put(Object data){
          rwl.writeLock().lock(); 
           try {
               System.out.println(Thread.currentThread().getName() + " be ready to write data!");
               Thread.sleep((long)(Math.random()*1000));
               this.data = data;
               System.out.println(Thread.currentThread().getName() + " have write data: " + data);
            } catch (InterruptedException e) {
               e.printStackTrace();
         }finally{
               rwl.writeLock().unlock();
          }
   } 
}


############################緩存系統示例代碼##############################

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheDemo {
         private Map cacheMap = new HashMap<String,Object>();
 
         public static void main(String[] args) {
         }
 
         private ReadWriteLock rwl = new ReentrantReadWriteLock();

         public Object get(int key) throws Exception{
              rwl.readLock().lock();
              Object value = null;
              try{
                   value = cacheMap.get(key);
                   if(value==null){
                        rwl.readLock().unlock();
                        rwl.writeLock().lock();
                        try{
                             value = "aaaa";//實際上是queryDB()
                             if(value == null){
                                  throw new Exception();
                             }
                              cacheMap.put(key, value);
                        }finally{
                             rwl.writeLock().unlock();
                        }
   
                    rwl.readLock().lock();
                }
        }finally{
              rwl.readLock().unlock();
        }
 
          return value;
     }
 
}


/**********13張孝祥_java5條件阻塞Condition的應用**************/

阻塞隊列

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;        
public class BoundedBuffer {
 
 
 final Lock lock = new ReentrantLock();
 final Condition notFull = lock.newCondition();// notFull  緩存不滿
 final Condition notEmpty = lock.newCondition();//notEmpty 緩存非空
 
 
 final Object[] items = new Object[100];
 int putptr,takeptr,count; 
 
 public void put(Object x) throws InterruptedException{
      lock.lock();
      try{
   
           while(count==items.length)
                    notFull.await();//緩存不滿這個條件是假的 及意思是 緩存是滿的
   
           items[putptr]=x;
           if(++putptr==items.length) putptr=0;
           ++count;
   
           notEmpty.signal();//緩存非空這個條件是真的
   
      }finally{
           lock.unlock();
      }
 }
   
 public Object take() throws InterruptedException{ 
     lock.lock();
     try{
          while(count==0)
               notEmpty.await();//緩存非空這個條件是假的   及意思是  現在緩存是空的
     
          Object x = items[takeptr];
          if(++takeptr==items.length) takeptr=0;
          --count;
     
          notFull.signal();//緩存不滿這個條件是真的
          return x;
     
         }finally{
              lock.unlock();
         }
    }
}
i

/********************14張孝祥java5的Semaphere同步工具**************************/

Semaphore可以維護當前訪問自身的線程個數,並提供了同步機制。使用Semaphore可以控制同時訪問資源的線程個數,例如,實現一個文件允許的併發訪問數。
Semaphore實現的功能就類似廁所有5個坑,假如有十個人要上廁所,那麼同時能有多少個人去上廁所呢?同時只能有5個人能夠佔用,當5個人中的任何一個人讓開後,其中在等待的另外5個人中又有一個可以佔用了。 另外等待的5個人中可以是隨機獲得優先機會,也可以是按照先來後到的順序獲得機會,這取決於構造Semaphore對象時傳入的參數選項。
單個信號量的Semaphore對象可以實現互斥鎖的功能,並且可以是由一個線程獲得了“鎖”,再由另一個線程釋放“鎖”,這可應用於死鎖恢復的一些場合。


package cn.itcast.heima2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class TwoTest {
         public static void main(String[] args) { 
               ExecutorService executorService = Executors.newCachedThreadPool();
               final Semaphore semaphore = new Semaphore(3);
               for(int i=0;i<10;i++){ 
                    Runnable runnable = new Runnable() {
                              public void run() { 
                                      try { 
                                              semaphore.acquire(); 
                                              System.out.println("線程" + Thread.currentThread().getName() + "進入,當前已有" + (3-semaphore.availablePermits()) + "個併發"); 
     
                                              Thread.sleep((long) (Math.random()*10000));
     
                                              System.out.println("線程" + Thread.currentThread().getName() + "即將離開");   
                                              semaphore.release();
     
                                              //下面代碼有時候執行不準確,因爲其沒有和上面的代碼合成原子單元
                                              System.out.println("線程" + Thread.currentThread().getName() + "已離開,當前已有" + (3-semaphore.availablePermits()) + "個併發"); 
     
                                          } catch (InterruptedException e) {
                                                   e.printStackTrace();
                                          }
     
                 }
            };
            executorService.execute(runnable);
       }
  }



/*********15張孝祥java5的CyclicBarrier同步工具************/

表示大家彼此等待,大家集合好後纔開始出發,分散活動後又在指定地點集合碰面,這就好比整個公司的人員利用週末時間集體郊遊一樣,先各自從家出發到公司集合後,再同時出發到公園遊玩,在指定地點集合後再同時開始就餐,…。   

import java.util.Random;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
 
     public static void main(String[] args) {
               ExecutorService executorService = Executors.newCachedThreadPool();
               final CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
     
              for(int i=1;i<=3;i++){
        
                       Runnable runnable = new Runnable() {
     
                             public void run() {
     
                                          try {
                                                   Thread.sleep((long) (Math.random()*10000));
                                                   System.out.println("線程"+Thread.currentThread().getName()+"即將到達集合點1" +
                                                     ",當前已有"+(cyclicBarrier.getNumberWaiting()+1)+"個到達集合點," +
                                                   (cyclicBarrier.getNumberWaiting()==2?"都到齊了,繼續走啊":"正在等候"));
                                                   cyclicBarrier.await();
         
                                                  Thread.sleep((long) (Math.random()*10000));
         
                                                  System.out.println("線程" + Thread.currentThread().getName() +
                                                 "即將到達集合地點2,當前已有" + (cyclicBarrier.getNumberWaiting()+1) + "個已經到達," + (cyclicBarrier.getNumberWaiting()==2?"都到齊了,繼續走啊":"正在等候"));
         
                                                   cyclicBarrier.await();
                                                   Thread.sleep((long)(Math.random()*10000));
                                                   System.out.println("線程" + Thread.currentThread().getName() +
                                                   "即將到達集合地點3,當前已有" + (cyclicBarrier.getNumberWaiting() + 1) + "個已經到達," + (cyclicBarrier.getNumberWaiting()==2?"都到齊了,繼續走啊":"正在等候"));
         
                                                   cyclicBarrier.await();
                                      } catch (Exception e) {
                                           e.printStackTrace();
                                      }
     
                     }
            };
   
               executorService.execute(runnable);
        }
      executorService.shutdown();
   }
 }
/*********16張孝祥java5的CountDownLatch同步工具**********/

猶如倒計時計數器,調用CountDownLatch對象的countDown方法就將計數器減1,當計數到達0時,則所有等待者或單個等待者開始執行。這直接通過代碼來說明CountDownLatch的作用,這樣學員的理解效果更直接。 
可以實現一個人(也可以是多個人)等待其他所有人都來通知他,這猶如一個計劃需要多個領導都簽字後才能繼續向下實施。還可以實現一個人通知多個人的效果,類似裁判一聲口令,運動員同時開始奔跑。用這個功能做百米賽跑的遊戲程序不錯哦!

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class CountDownLatch {

         public static void main(String[] args) {
               ExecutorService executorService = Executors.newCachedThreadPool();
               final java.util.concurrent.CountDownLatch orderCount = new java.util.concurrent.CountDownLatch(1);
               final java.util.concurrent.CountDownLatch ansCount = new java.util.concurrent.CountDownLatch(3);
          
              for(int i=1;i<=3;i++){
                      Runnable runnable = new Runnable() {
     
                                 public void run() {
                                          System.out.println("線程" + Thread.currentThread().getName() +"正準備接受命令");   
                                          try {
                                               orderCount.await();
                                               System.out.println("線程" + Thread.currentThread().getName() +  "已接受命令");  
                                               Thread.sleep((long)(Math.random()*10000));
                                               System.out.println("線程" + Thread.currentThread().getName() +   "迴應命令處理結果"); 
                                               ansCount.countDown();
       
                                           } catch (InterruptedException e) {
                                                e.printStackTrace();
                                          }
                             }
                    };
   
                   executorService.execute(runnable);
             }
         
        try {  
         
              Thread.sleep((long)(Math.random()*10000));
              System.out.println("線程" + Thread.currentThread().getName() +  "即將發佈命令"); 
              orderCount.countDown();
              System.out.println("線程" + Thread.currentThread().getName() +"已發送命令,正在等待結果");  
              ansCount.await();
              System.out.println("線程" + Thread.currentThread().getName() +"已收到所有響應結果");  

         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         executorService.shutdown(); 
         
  


/*********17張孝祥java5的Exchanger同步工具*************/
用於實現兩個人之間的數據交換,每個人在完成一定的事務後想與對方交換數據,第一個先拿出數據的人將一直等待第二個人拿着數據到來時,才能彼此交換數據。


import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExchangerTest {

        public static void main(String[] args) {
                  ExecutorService executorService = Executors.newCachedThreadPool();
                  final Exchanger exchanger = new Exchanger();
   
                  executorService.execute(new Runnable() {
   
                           public void run() { 
   
                                   try {
                                            String data1 = "毒品";
                                            System.out.println("線程" + Thread.currentThread().getName() +"正在把" + data1 +"換出去");
                                            Thread.sleep((long) (Math.random()*10000));
                                            String data2 = (String) exchanger.exchange(data1);
                                            System.out.println("線程" + Thread.currentThread().getName() + "換回" + data2);
     
                                } catch (InterruptedException e) {
                                            e.printStackTrace();
                                }
                           }
                  });
     
             executorService.execute(new Runnable() {  
   
                           public void run() {
   
                                    try {
                                             String data1 = "美金";
                                             System.out.println("線程" + Thread.currentThread().getName() +"正在把" + data1 +"換出去");
                                             Thread.sleep((long) (Math.random()*10000));
                                             String data2 = (String) exchanger.exchange(data1);
                                             System.out.println("線程" + Thread.currentThread().getName() + "換回" + data2);
                                        } catch (InterruptedException e) {
                                             // TODO Auto-generated catch block
                                             e.printStackTrace();
                                        }
   
                           }
   
                });
        }
}


/***************18張孝祥java5阻塞隊列的應用****************/

什麼是可阻塞隊列,阻塞隊列的作用與實際應用,阻塞隊列的實現原理。
阻塞隊列與Semaphore有些相似,但也不同,阻塞隊列是一方存放數據,另一方釋放數據,Semaphore通常則是由同一方設置和釋放信號量。

ArrayBlockingQueue 只有put方法和take方法才具有阻塞功能

用3個空間的隊列來演示阻塞隊列的功能和效果。

import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
public class BlockQueueTest {
 /**
  * @param args 
  */
 public static void main(String[] args) {
           final BlockingQueue blockingQueue = new ArrayBlockingQueue(3);
           for(int i=1;i<=2;i++){
                new Thread(new Runnable() {
     
                         public void run() {
       
                              while(true){
                                   try {
                                        Thread.sleep((long) (Math.random()*10000));
                                        System.out.println(Thread.currentThread().getName()+"準備放數據");
                                        blockingQueue.put(1);
                                        System.out.println(Thread.currentThread().getName()+"放數據成功"+"當前隊列有"+blockingQueue.size()+"個數據");
       
                                   } catch (Exception e) {
                                        e.printStackTrace();
                                   }
                              }
     
                     }
             }).start();
        }
   
           new Thread(new Runnable() {
   
                    public void run() {
                             while(true){
                                      try {
                                           Thread.sleep((long) (Math.random()*10000));
                                           System.out.println(Thread.currentThread().getName() + "準備取數據!");
                                           blockingQueue.take();
                                           System.out.println(Thread.currentThread().getName()+"取數據成功"+"當前隊列有"+blockingQueue.size()+"個數據");
                                      } catch (InterruptedException e) {
                                           e.printStackTrace();
                                       }
                             }
                    }
        }).start();
   }
}

用兩個具有1個空間的隊列來實現同步通知的功能。 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class BlockingQueueCommunicationTest {
     public static void main(String[] args) {
   
          new BlockingQueueCommunicationTest().execute(); 
    
    private void execute(){
              final Business business = new Business();
 
              new Thread(new Runnable() {
   
                   public void run() {
                        for(int j=1;j<=100;j++){
                             business.sub(j);
                        }
                   }
              }).start();
 
              for(int j=1;j<=100;j++){
                   business.main(j);
              }
 
     }
 
     private class Business{
 
          BlockingQueue blockingQueue1 = new ArrayBlockingQueue(1);
          BlockingQueue blockingQueue2 = new ArrayBlockingQueue(1);
         
         //匿名構造方法,先於非匿名構造方法執行
          {
                   try {
                        blockingQueue2.put(1);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
          }
   
        public void sub(int j){
                try {
                    blockingQueue1.put(1);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
               for(int i=1;i<=10;i++){
                    System.out.println("sub thread sequece of " + i + ",loop of " + j);
               }
               try {
                    blockingQueue2.take();
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
   
     }
 
    public void main(int j){
           try {
                blockingQueue2.put(1);
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
           for(int i=1;i<=10;i++){
                System.out.println("main thread sequece of " + i + ",loop of " + j);
           }
           try {
                blockingQueue1.take();
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
    }
  }
}




















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