Java 多線程相關的使用

線程的創建

1.繼承Thread類,重寫run方法;
2.實現Runnable接口 重寫run方法;

區別
使用Runnable接口的更適合面向對象的思想,可以使線程類繼承其他父類。多個線程處理一個Runnable等問題。

join/wait/notify

join 調用此方法的線程在調用之前執行完畢

  ....thread1.....
  thread1.join()
  ....thread2.....

線程本來是異步的,在沒加入join時候,如果兩個線程同時執行是不知道兩個線程執行的先後順序的,但加入join後,join調用的線程限制性完畢後,在執行join下面的代碼。
wait 與notify 區別
wait 線程休眠,釋放鎖,讓出CPU,進入休眠
notify 喚醒休眠的線程

使用範例

while(conditioin){
  try{
    wait();
  }catch(Exception e){

  }
  .......
}

另外地方 notify() 喚醒休眠線程

線程的掛起和線程的等待的區別:

  • 線程的掛起:被動的,保護現場(頁面和寄存器等),內存交出去,跟中斷一樣
  • 線程的等待:主動的,不需要保護線程,內存一直佔用等待某種結果

鎖實現同步Lock/ReentrantLock/ReadWriteLock/ReentrantReadWriteLock

  • ReentrantLock的使用
Lock lock = new ReentrantLock();
lock.lock();
...臨界區...
lock.unlock();

注意:unlock解鎖一定要放到try() finilly {…unlock};

  • ReentrantReadWriteLock讀寫鎖的使用
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

//讀數據時候
readWriteLock.readLock().lock();
//讀臨界區
readWriteLock.readLock.unlock();
....
//寫數據時候
readWriteLock.writeLock().lock();
//寫臨界區
readWriteLock.writeLock.unlock();

讀寫鎖和重入鎖不同的是,讀寫鎖在讀的時候是運行多個線程訪問資源,寫時候只允許一個線程訪問臨界資源。

  • 鎖中的多條件使用
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

//代碼執行
lock.lock();
while(條件){
  try{
    condition.await();
   }catch(Exceptioin e){
   }
}
.....//臨界區代碼
condition.signal();//通知喚醒休眠的線程
lock.unlock();

鎖的多條件使用與前面的wait/notify類似,只是wait/notify與關鍵字synchroniced一起使用,而鎖不需要在方法名前面添加關鍵字。

線程同步輔助類

  • CountDownLatch
public CountDownLatch(int count) {  };  //參數count爲計數值
public void await() throws InterruptedException { };   //調用await()方法的線程會被掛起,它會等待直到count值爲0才繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  //和await()類似,只不過等待一定的時間後count值還沒變爲0的話就會繼續執行
public void countDown() { };  //將count值減1

基本工作原理:count計數值爲零時候,await()被喚醒往下執行,不然一直阻塞在這裏。

  • Semaphore
public void acquire() throws InterruptedException {  }     //獲取一個許可
public void acquire(int permits) throws InterruptedException { }    //獲取permits個許可
public void release() { }          //釋放一個許可
public void release(int permits) { }    //釋放permits個許可

基本工作原理:獲取信號,相當於鎖;沒有獲取到時候阻塞等待

  • CyclicBarier
public int await() throws InterruptedException, BrokenBarrierException { };
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };

基本工作原理:所有的線程都到達barier後開始執行

  • Exchanger 線程數據交互

    exchange(V v) //交換數據

基本工作原理:將相同的Exchanger實例在不同的線程中進行數據交換

線程池

線程池就是事先將多個線程對象放到一個容器中,當使用的時候就不用new 線程而是直接去池中拿線程即可,節省了開闢子線程的時間,提高的代碼執行效率。

  1. 減少在創建和銷燬線程上所花的時間以及系統資源的開銷
  2. 如不使用線程池,有可能造成系統創建大量線程而導致消耗完系統內存以及”過度切換
Java四種線程池使用方法
  • 4.1 newCachedThreadPool
    創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
ExecutorService executorService = Executors.newCachedThreadPool();
    executorService.execute(new Runnable() {
         @Override
         public void run() {

         }
});
  • 4.2 newFixedThreadPool
    創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
ExecutorService executorService1 = Executors.newFixedThreadPool(3);
    executorService1.execute(new Runnable() {
          @Override
          public void run() {

          }
});
  • 4.3 newScheduledThreadPool
    創建一個定長線程池,支持定時及週期性任務執行
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
    scheduledExecutorService.schedule(new Runnable() {
         @Override
         public void run() {

         }
}, 3, TimeUnit.MINUTES);
  • 4.4 newSingleThreadExecutor
    創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
ExecutorService executorService2 = Executors.newSingleThreadExecutor();
    executorService2.execute(new Runnable() {
          @Override
          public void run() {

          }
});

Fork/Join框架

分解合併框架,通過分治技術將問題按照一定的規則拆分成很多小問題來處理。

主要編程步驟:

XXXTask xxxTask = new XXXTask();
ForkJoinPool pool = new ForkJoinPool();
pool.execute(xxxTask);

XXXTask這裏分爲兩種情況:
無返回參數的:

class XXXTask extends RecursiveAction  //(RecursiveAction extends ForkJoinTask<Void>)
//然後到實現compute方法,進行分治邏輯處理

有參數的:

class XXXTask extends RecursiveTask<T> //(RecursiveTask<T> extends ForkJoinTask<T>)
//然後到實現compute方法,進行分治邏輯處理,記得返回參數合併問題。直接可以通過task.get()方法拿到返回值。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章