1. 程式人生 > >關於多執行緒的一些瞭解

關於多執行緒的一些瞭解

補充之前的學習筆記

1JUC是什麼

1.1 Java.util.concurrent =JUC

1.2 程序:系統裡執行的多個程式QQ.exe     執行緒:一個程序中有多個執行緒

1.3 執行緒的多種狀態。

.start()--就緒狀態

State:

new建立  runnable啟動  blocked阻塞 waiting等待(不見不散) timed_waiting等待(過時不候) terminated終結

1.4  wait交鎖  sleep不交鎖

1.5  併發:同一時間點多個執行緒訪問同一個資源           並行:同時執行多個資源

 

2、lambda表示式

①寫法:拷貝中括號+寫死右箭頭+落地大括號

②只有函式介面(接口裡只有一個方法時)才能用lambda表示式

③介面上標記@FunctionalInterface

Foo foo = () -> {業務邏輯程式碼,實現方法}

④default方法的實現

用@FunctionalInterface的介面只能有個一方法,但是可以又多個default方法

⑤靜態方法實現

用@FunctionalInterface的介面只能有個一方法,但是可以又多個default方法,可以有多個靜態方法

 

3、執行緒間的通訊

3.1生產者+消費者

3.2通知等待喚醒機制

判斷   幹活    通知

3.3 2個執行緒變4個執行緒,禁止出現虛假喚醒,判斷條件用while

3.4  

----------------lock-----------------   

Lock lock=new   ReentrantLock();

Condition condition = lock.newCondition();

condition.awati();    codittion.signalAll();           

-------------------syncronised-----------------    

          |                             |

      wait();                       notifiyAll();

 

4、傳值和傳引用

基本型別傳影印件

引用型別傳引用

String型別比較特殊,因為有個池的概念,所以相當於指向變了,但是原來的指標還是指向原來的引用

 

5、Callable

callable:有異常、有返回值、call

runnable:無異常、無返回值、run

FutureTask作用:非同步呼叫

自頂向下,逐步求精

一個futuretask被多個執行緒呼叫,結果可以複用

futureTask.get()只允許放到最後,get方法只計算一次 

-----------------原理,底層------------------

①在主執行緒中需要執行比較耗時的操作時,但又不想阻塞主執行緒時,可以把這些作業交給Future物件在後臺完成,當主執行緒將來需要時,就可以通過future物件獲得後臺作業的計算結果或者執行狀態。

②一般FutureTask多用於耗時的計算,主執行緒可以在完成自己的任務後,再去獲取結果

③僅再計算完成時才能檢索結果,如果計算尚未完成,則阻塞get方法,一旦計算完成,就不能再重新開始或者取消計算,get方法獲取結果只有再計算完成時獲取,否則會一直阻塞直到任務轉入完成狀態,然後會返回結果或者丟擲異常。

 

6、ReadWriteLock

ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock ();

rwLock .writeLock().lock();

rwLock .readLock().lock();

讀寫鎖案例:讀可共享,寫排他

 

class ReadWrite{

      private Object obj;

      private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

      

      public void writeLock(Object obj){

             rwLock.writeLock().lock();

             try {

                   this. obj = obj;

                  System. out.println(Thread. currentThread().getName()+"寫執行緒正在執行\t"+obj);

            } catch (Exception e) {

                   // TODO: handle exception

            } finally{

                   rwLock.writeLock().unlock();

            }

      }

      

      public void readLock(){

             rwLock.readLock().lock();

             try {

                  System. out.println(Thread. currentThread().getName()+"讀執行緒正在執行\t"+obj);

            } catch (Exception e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

            } finally{

                   rwLock.readLock().unlock();

            }

      }

      

}

 

 

7、執行緒池

ExecutorService service=Executors.newFixedThreadPool(5);//一池5執行緒(核心執行緒=最大執行緒=5)

  • 阻塞佇列採用了LinkedBlockingQueue,它是一個無界佇列;

  • 由於阻塞佇列是一個無界佇列,因此永遠不可能拒絕任務;

  • 由於採用了無界佇列,實際執行緒數量將永遠維持在nThreads,因此maximumPoolSize和keepAliveTime將無效。

 

    public static ExecutorService newFixedThreadPool( int nThreads) {

        return new ThreadPoolExecutor( nThreads, nThreads ,

                                      0L, TimeUnit. MILLISECONDS,

                                      new LinkedBlockingQueue<Runnable>());

    }

ExecutorService service=Executors.newSingleThreadExecutor();//一池1執行緒(核心執行緒=最大執行緒=1)

 

 public static ExecutorService newSingleThreadExecutor() {

        return new FinalizableDelegatedExecutorService

            ( new ThreadPoolExecutor(1, 1,

                                    0L, TimeUnit. MILLISECONDS,

                                    new LinkedBlockingQueue<Runnable>()));

    }

 

ExecutorService service=Executors.newCachedThreadPool();//一池N執行緒(核心執行緒0,最大執行緒int的最大值相當於沒有上限)

  • 它是一個可以無限擴大的執行緒池;

  • 它比較適合處理執行時間比較小的任務;

  • corePoolSize為0,maximumPoolSize為無限大,意味著執行緒數量可以無限大;

  • keepAliveTime為60S,意味著執行緒空閒時間超過60S就會被殺死;

  • 採用SynchronousQueue裝等待的任務,這個阻塞佇列沒有儲存空間,這意味著只要有請求到來,就必須要找到一條工作執行緒處理他,如果當前沒有空閒的執行緒,那麼就會再建立一條新的執行緒。

 

public static ExecutorService newCachedThreadPool () {

  return new ThreadPoolExecutor(0, Integer. MAX_VALUE,

                                      60L, TimeUnit. SECONDS,

                                      new SynchronousQueue<Runnable>());

}

 

service.submit(Runnable);

service.shutdown();

---------------------------------

ScheduledExecutorService service=Executors.newScheduledThreadPool(5);//時間輪詢,每隔多少時間執行一個任務,如果執行緒忙不過來會自動新加執行緒(核心執行緒5,最大執行緒int最大值相當於沒有上限)

  • 它採用DelayQueue儲存等待的任務

  • DelayQueue內部封裝了一個PriorityQueue,它會根據time的先後時間排序,若time相同則根據sequenceNumber排序;

  • DelayQueue也是一個無界佇列;

  • 工作執行緒的執行過程:

  • 工作執行緒會從DelayQueue取已經到期的任務去執行;

  • 執行結束後重新設定任務的到期時間,再次放回DelayQueue

 

     public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {

        return new ScheduledThreadPoolExecutor( corePoolSize);

     }

    public ScheduledThreadPoolExecutor( int corePoolSize) {

        super(corePoolSize, Integer. MAX_VALUE, 0, TimeUnit. NANOSECONDS,

              new DelayedWorkQueue());

     }

     public ThreadPoolExecutor( int corePoolSize,

                              int maximumPoolSize,

                              long keepAliveTime,

                              TimeUnit unit,

                              BlockingQueue<Runnable> workQueue) {

        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

             Executors. defaultThreadFactory(), defaultHandler);

     }

service.schedule(callable,delay,unit);//執行緒,延遲,時間單位   每隔2s提交一次請求

 

public class ReadWriteLock {

      public static <E> void main(String[] args) {

            

            ExecutorService service = Executors. newCachedThreadPool();

            

             final ReadWrite readWrite = new ReadWrite();

            

             try {

                  Thread thread1 = new Thread( new Runnable() {

                         @Override

                         public void run() {

                               readWrite.writeLock( "this is write");

                              

                        }

                  }, "AA");

                   service.execute( thread1);     

                  

                   for( int i=1; i<=100; i++){

                        Thread thread2 = new Thread( new Runnable() {

                               @Override

                               public void run() {

                                     readWrite.readLock();

                              }

                        }, String. valueOf(i));

                         service.execute( thread2);

                  }

            } catch (Exception e) {

                   // TODO Auto-generated catch block

                   e.printStackTrace();

            } finally{

                   service.shutdown();

            }

      }

}

 

 

8、常用工具類

CountDownLatch----所有執行緒執行完才執行的任務(秦滅六國,一統華夏)

final CountDownLatch countDownLatch = new CountDownLatch(6);

countDownLatch .countDown();//沒執行一條就-1,直到6條都執行完

countDownLatch .await();//阻塞最後一個要執行的主執行緒

 

public class CountDownLatchDemo {

      

      public static void main(String[] args) throws InterruptedException {

             //CountDownLatch

             final CountDownLatch countDownLatch = new CountDownLatch(6);

            

             for( int i=1; i<=6; i++){

                   new Thread( new Runnable() {

                        

                         @Override

                         public void run() {

                              System. out.println(Thread. currentThread().getName()+"\t 國家被滅");

                               countDownLatch.countDown();

                        }

                  }, CountryEnums.forEachCountryEnums(i).getMsg()).start();

            }

            

             countDownLatch.await();

            System. out.println(Thread. currentThread().getName()+"\t 秦滅六國,一統華夏" );

      }

}

 

 

CyclicBarrier---集齊7顆龍珠,可以召喚神龍(其他執行緒執行完了只能等待)

 

public class CyclicBarrierDemo {

      

      private final static int number=7;

      

      public static void main(String[] args) {

             final CyclicBarrier cyclicBarrier = new CyclicBarrier(number, new Runnable() {

                   @Override

                   public void run() {

                        System. out.println( "集齊7顆龍珠,可以召喚神龍" );

                  }

            });

             for( int i=1; i<=7; i++){

                   final int temp= i;

                   new Thread( new Runnable() {

                         @Override

                         public void run() {

                               try {

                                    System. out.println(Thread. currentThread().getName()+"\t 收集第"+ temp+ "顆龍珠");

                                     cyclicBarrier.await();

                              } catch (InterruptedException | BrokenBarrierException e) {

                                     e.printStackTrace();

                              }

                        }

                  }, String. valueOf(i)).start();

            }

            

      }

}

 

Semaphore----訊號燈(爭車位)

 

public class SemaphoreDemo {

      public static void main(String[] args) {

             final Semaphore semaphore = new Semaphore(3); //模擬3個停車位

             for( int i=1; i<=6; i++){ //模擬6個汽車

                   new Thread( new Runnable() {

                        

                         @Override

                         public void run() {

                               try {

                                     semaphore.acquire();

                                    System. out.println(Thread. currentThread().getName()+ "\t 搶佔到停車位" );

                                    TimeUnit. SECONDS.sleep( new Random().nextInt(5));

                                    System. out.println(Thread. currentThread().getName()+ "\t---- 離開了停車位" );

                              } catch (InterruptedException e) {

                                     e.printStackTrace();

                              } finally{

                                     semaphore.release();

                              }

                              

                        }

                  }, String. valueOf(i)).start();

            }

      }

}

 

9、集合不安全類

ArrayList、HashMap、HashSet

java.util.ConcurrentModificationException

CopyOnWriteArrayList();//寫時複製

往元素中新增元素時,先複製一份新的陣列(Arrays.copyOf),長度+1,把要新增的元素新增到新的陣列中。最後把引用指向新的陣列。(整個過程添加了reentrainLock)

CopyOnWriteArraySet<String>();

ConcurrentHashMap<>();

sss---->Arrays  Collections

三者對比:

 

1)CountDownLatch和CyclicBarrier都能夠實現執行緒之間的等待,只不過它們側重點不同:

CountDownLatch一般用於某個執行緒A等待若干個其他執行緒執行完任務之後,它才執行;

而CyclicBarrier一般用於一組執行緒互相等待至某個狀態,然後這一組執行緒再同時執行;

另外,CountDownLatch是不能夠重用的,而CyclicBarrier是可以重用的。

2)Semaphore其實和鎖有點類似,它一般用於控制對某組資源的訪問許可權。

 

 

10、volatile

記憶體可見性 

 

public class SafeSingletonDemo {

      private static volatile SafeSingletonDemo safeSingletonDemo = null;

      private SafeSingletonDemo(){

            System. out.println( "********"+Thread. currentThread().getName());

      }

      

      //double check lock

      public static SafeSingletonDemo getInstance(){

             if( null == safeSingletonDemo){

                   synchronized (SafeSingletonDemo. class) {

                         if( null == safeSingletonDemo){

                               safeSingletonDemo= new SafeSingletonDemo();

                        }

                  }

            }

             return safeSingletonDemo;

      }

      

      public static void main(String[] args) {

             new Thread( new Runnable() {

                  

                   @Override

                   public void run() {

                        SafeSingletonDemo. getInstance();

                  }

            }, "AA").start();

             new Thread( new Runnable() {

                  

                   @Override

                   public void run() {

                        SafeSingletonDemo. getInstance();

                  }

            }, "BB").start();

             new Thread( new Runnable() {

                  

                   @Override

                   public void run() {

                        SafeSingletonDemo. getInstance();

                  }

            }, "CC").start();

      }

}

彩蛋:某次公開課中記錄的筆記

擊穿快取的方法:

口訣:讀多寫少用快取,寫多讀少用佇列,限流、分流

方法1:化併發為同步   

lock:等待鎖:粗粒度的鎖

1個執行緒拿到鎖,重建快取,

其他1999個執行緒等待,從redis取

方法2:互斥鎖ConcurrentHashMap<> map     細粒度的鎖

車次號1-->是否有鎖

車次號2-->是否有鎖

boolean lock = false;

lock = map.putIfAbsent(key,value)==null;//代表當前沒有資料,不為null,當前有資料

if(lock){//拿到鎖

     //重建快取

     //再查一次

}else{//沒拿到鎖

     //快取降級

     1:提示:當前人數太多,請耐心等待

}