中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

關于Java的并發編程

發布時間:2020-07-20 16:29:59 來源:網絡 閱讀:142 作者:nineteens 欄目:編程語言

  關于JAVA并發編程的那些事。

  記錄一下自己在學習并發編程的時候遇到的一些問題。方便自己查閱。

  1.實現Runnable接口好在哪里?

  從代碼架構角度:具體的任務(run方法)應該和“創建和運行線程的機制”(Thread類)相解耦。

  使用繼承Thread類的方式的話,那么每次想新建一個任務,只能新建一個獨立的線程們這樣做的話損耗會比較大(比如重新創建一個線程,執行完畢

  以后再銷毀等。如果實際工作內容,也就是run()函數里只是簡單的打印一行文字的話,那么可能線程的實際工作內容還不如損耗來的大)。如果使用Runnable和線程池,就可以大大減少這樣的損耗。

  繼承Thread類以后,由于Java語音不支持多繼承,這樣就無法再繼承其他的類,限制了可擴展性。

  2.“實現Runnable接口并傳入Thread類”和繼承Thread類,然后重寫run()方法的本質對比?

  在實現多線程的本質上,并沒有區別,都是最終調用了start()方法來新建線程。這兩個方法最主要的區別是在于run()的了內容來源。

  //以下代碼在Thread類中,可以找到

  @override

  public void run(){

  if(target!=null){

  target.run();

  }

  }

  實現Runnable接口最終調用target.run()。繼承Thread類,是整個run()方法都被重寫。

  3.有幾種創建線程的方法?

  從不同的角度看,會有不同的答案。

  典型答案是兩種,分別是實現Runnable接口和繼承Thread類

  但是我們看原理,其實Thread類實現了Runnable接口,并且Thread類的run()方法,會發現其實哪兩種本質是一樣的。兩種方式在實現多線程的本質上,并沒有區別。

  還有其他實現線程的方法,例如線程池等,他們也能新建線程,但是細看源碼,并沒有逃過本質,也是實現Runnable接口和繼承Thread類。

  結論:我們只能那個通過新建Thread類這一種方式來出創建線程,但是類里面的run方法有兩種方式實現,的一種是重寫run()方法,第二種是實現Runnable接口的run方法,然后再把該Runnable實例傳給Thread類。除此之外,從表面上看線程池、定時器等工具類也能創建線程,但是他們的本質也是逃不過剛說的范圍。

  4.start方法的執行流程是什么?

  檢查線程狀態,只有New狀態的線程才能繼續,否則會拋出IllegalThreadStateException。運行或已經結束的線程都不能再啟動。

  (這里可引申面試題:一個線程調用兩次start()方法會出現什么情況?why?解題思路就是1異常2線程狀態)

  被加入線程組

  調用start0()方法啟動線程。

  Tips:start方法是被synchronized修飾的方法,可以保證線程安全。并且由JVM產檢的main方法和system組線程,并不會通過start來啟動。

  5.Java中如何正確停止線程?

  用interrupt來請求停止線程。(僅僅是通知到被終止的線程應該停止運行了,被停止的線程自身擁有決定權。這是一個協作機制。)

  想要停止線程,需要請求方,被停止方,子方法被調用方相互配合才行:

  – a.作為被停止方:每次循環或者適時檢測中斷信號,并且在可能拋出interruptedException的地方處理該中斷信號;

  – b.請求方:發出中斷信號。

  – c.子方法調用方:要注意優先在方法拋出InterruptedException,或者在檢查到中斷信號時,再次設置中斷狀態。(Catch里會重置這個狀態,需要再次設置中斷狀態,否則就被吞了)

  最后,錯誤的方法: stop、suspend方法已經被廢棄(stop容易造成臟數據)

  volatile的boolean標記,無法處理長時間阻塞的情況(例如,生產者消費者模式中,就存在這樣的情況,生產者生產速度快,消費者消費速度慢,生產者隊列阻塞)

  6.無法響應中斷時如何停止線程?

  如果線程阻塞是由于調用了wait()、sleep()或者join()方法,你可以中斷線程,通過拋出interruptedException異常來喚醒該線程,但是對于不能響應InterruptedException的阻塞,并沒有一個通用的解決方案。但是我們可以利用特定的其他可以響應中斷的方法,比如Reentrantlock.lockInterruptibly(),比如關閉套接字使線程立即返回等方法來達到目的。答案有很多種,因為有很多原因會造成線程阻塞,所以針對不同的情況,喚起的方法不同。總結來說,如果不支持響應中斷,就要用特定的方法來喚起。根據不同的類,調用不同的方法。

  .可以響應中斷而拋出InterruptedException的常見方法?

  Object.wait()/wait(long)/wait(long,int)

  Thread.sleep()/sleep(long,int)

  Thread.join()/join(long)/join(long,int)

  java.util.concurrent.BlockingQueue.take()/put(E)

  java.util.concurrent.locks.Lock.lockInterruptibly()

  java.util.concurrent.countDownLatch.await()

  java.util.concurrent.cyclicBarrier.await()

  java.uti.concurrent.Exchanger.exchange(V)

  java.nio.channels.InterruptibleChannel相關方法

  java.nio.channels.Selector相關方法

  7.判斷線程是否被中斷的方法有哪些?

  static boolean interrupted() //返回之后,清除標記

  boolean isInterrupted() //不清除

  //Tip:注意Thread.intterupted()的目的對象時“當前線程”,而不管本方法來自于哪個對象

  8.線程都有哪幾個狀態?

  6種狀態

  New:已經創建,但是還沒有執行start方法

  Runnable:一旦調用了start方法后,就一定會到Runnable,java中的Runnable對應操作系統里的ready和running狀態

  Blocked:當一個線程進入同步代碼塊(被Synchronized修飾),該鎖被其他線程拿走了。線程變成Blocked。只有Synchronized才能rag線程進入這個狀態。

  Wating:等待

  Time_waiting:計時等待

  Terminated:死亡

  9.線程相關方法

  Thread類:

  sleep相關、

  join() :等待其他線程執行完畢

  yield相關 :放棄已經獲得的CPU資源

  currentThread:獲取當前線程的引用

  start,run方法:啟動線程相關

  interrupt相關::中斷線程

  stop() suspend() resuem()相關 :已經廢棄

  Object類:

  wait():讓線程短暫休息

  notify/notifyAll 相關 :喚醒線程

  10.wait/notify/notifyAll的作用和用法?

  階段  方法和作用

  阻塞階段  調用wait()方法

  喚醒階段  1、另一個線程調用這個對象的notify方法且剛好被喚醒的是本線程。2、另外一個線程調用這個對象的notifyAll方法。3、過了wait(long timeOut)的規定的超時時間,如果傳入0就是永久等待。4、線程自身調用了intterrupt()

  遇到中斷  wait階段遇到中斷會拋出異常,并且釋放掉鎖

  11.wait、notify、notifyAll特點?性質?

  用必須先擁有monitor鎖。(Synchronized)

  notify只能喚醒一個線程。

  屬于Object類,是所有對象的父類,所以任何對象都能調用,并且都是native final的。

  類似Condition的功能

  同時持有多個鎖的情況。釋放鎖,只能釋放現在wait所對應的對象的那把鎖。

  12.用wait/notify方法實現消費者生產者模式?

  package com.yue.consumer;

  import java.util.Date;

  import java.util.LinkedList;

  //使用wait notify實現一個生產者消費者模式

  public class ProducerConsumerModel {

  public static void main(String[] args) {

  EventStorage storage = new EventStorage();

  Producer producer = new Producer(storage);

  Consumer consumer =new Consumer(storage);

  new Thread(producer).start();

  new Thread(consumer).start();

  }

  }

  class Producer implements Runnable{

  private EventStorage storage;

  public Producer(EventStorage storage) {

  this.storage = storage;

  }

  public void run() {

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

  storage.put();

  }

  }

  }

  class Consumer implements Runnable{

  private EventStorage storage;

  public Consumer(EventStorage storage) {

  this.storage = storage;

  }

  public void run() {

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

  storage.take();

  }

  }

  }

  class EventStorage{

  private int maxSize;

  private LinkedList storage;

  public EventStorage() {

  this.maxSize = 10;

  this.storage = new LinkedList();

  }

  public synchronized void put(){

  while(storage.size() == maxSize){

  try {

  wait();

  }catch (InterruptedException e){

  e.printStackTrace();

  }

  }

  storage.add(new Date());

  System.out.println("倉庫里有了"+storage.size()+"個產品");

  notify();

  }

  public synchronized void take(){

  while(storage.size()==0){

  try {

  wait();

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  }鄭州婦科在線醫生 http://www.zzkdfk120.com/

  System.out.println("拿到了"+storage.poll()+",現在倉庫還剩下"+storage.size());

  notify();

  }

  }

  13.為什么wait需要在同步代碼塊中使用,而sleep不需要?

  為了讓線程之間的通信更加可靠,防止死鎖或者永久等待。如果不放在synchronized中的話,那么久有可能在線程執行到一個wait之前,切換到另外一個線程。而另外一個線程執行完notify后,切換回來。這樣就沒有線程去喚醒它了。而sleep是針對自己線程的,和其他線程的關系不大。

  14.為什么wait、notify和notifyAll定義在object類中,sleep定義在Thread類中?

  因為在Java中,這三個操作都是所級別的操作,而鎖是針對對象的。鎖是綁定到對象中,而不是綁定到線程。

  15.wait是屬于Object對象的,那調用Thread.wait()會出現什么情況?

  會導致流程問題。因為在線程退出的時候,會自動執行一個notify

  16.sleep方法的作用?

  作用:讓線程在預期執行,其他時候不占用CPU資源

  特點:Sleep方法可以讓線程進入waiting狀態,并且不占用CPU資源,但是不釋放鎖(包含synchronized和lock),直到規定時間之后在執行。休眠期內如果被中斷,會拋出異常并清除中斷狀態。

  Tips:

  //這兩種方式其實都是一樣的,但是第一種比較優雅

  TimeUnit.SECONDS.sleep()

  Thread.sleep()

  17.wait和sleep方法的異同?

  相同:

  Wait和sleep方法都可以使線程阻塞,對應線程狀態是Waiting或Time_Waiting。

  wait和sleep方法都可以響應中斷Thread.interrupt()。

  不同點:

  wait方法的執行必須在同步方法中進行,而sleep則不需要。

  在同步方法里執行sleep方法時,不會釋放monitor鎖,但是wait方法會釋放monitor鎖。

  sleep方法短暫休眠之后會主動退出阻塞,而沒有指定時間的 wait方法則需要被其他線程中斷后才能退出阻塞。

  wait()和notify(),notifyAll()是Object類的方法,sleep()和yield()是Thread類的方法

  TIps:Java設計的時候把對象都當成一把鎖,對象頭中都有鎖的狀態

  18. join()方法的作用?

  作用:因為新線程加入我們,所以得等他執行完再出發;通常是,主線程等待子線程,而不是子線程等待主線程。例如一般是main等thread1執行完。join遇到中斷時候是主線程被中斷,是主線程拋出異常;在join期間狀態是waiting

  Tips:CountDownLatch或CyclicBarrier類封裝了join。建議使用封裝好的工具

  源碼:

  調用了thread.wait方法,而這方法會在thread執行結束后悔自動調用notify。這也是為什么不要使用這個的原因。

  19.yield()方法的作用?

  作用:釋放cpu時間片,線程狀態是runnable,而不是bolcked,也不是waiting。常用于并發包中。

  yield 和 sleep:

  sleep期間屬于被阻塞,yield不是阻塞,隨時是runable狀態。而且JVM是不保證遵循的。

  20.線程都有哪些屬性?

  編號(ID):每個編程都有自己的ID,用于標識不同的線程。

  名稱(Name):作用是讓用戶或者程序員在開發、調試或運行過程中,更容易區分每個不同的線程,定位問題等。

  是否是守護線程(isDeamon) :true代表該線程是守護線程,false代表線程是非守護線程,也就是用戶線程。

  – 作用:給用戶線程提供服務。例如垃圾處理器。

  – 特性:線程類型默認繼承自父線程。被誰啟動,一般都是JVM啟動的,(main)。不影響JVM退出。

  – 區別:整體無區別。唯一區別在于是否影響JVM退出。

  優先級(Priority):優先級這個屬性的目的是告訴線程調度器,用戶希望哪些線程相對多運行,哪些少運行。

  – 10個優先級,默認5.

  – 程序的設計不應該優先級

  21.實際工作中,如何全局處理異常?為什么要全局處理?不處理行不行?

  主線程可以啟動發現異常,子線程卻不行。比如主線程操作非常多,子線程雖然報異常,但是日志太多,不好發覺。并且在子線程發現問題后,并沒有停止執行。

  子線程異常無法用傳統方法捕獲。

  不能直接捕獲的后果,可能線程掛掉打印堆棧。用了全局處理之后提高健壯性,可以在發生未知異常后,重啟線程或者通知程序員等。

  22.關于線程異常的兩種處理方法?

  方案一:手動在每個run()方法里進行try catch (不推薦)

  方案二:利用UncaughtExceptionHanler接口

  – void uncaughtException (Thread t,Throwable e)

  – 異常處理器的調用策略:首先會檢查父線程,一直往上找,查找是否有人能夠處理。

  – 實現:

  首先,自定義一個類實現Thread.UncaughtExceptionHandler。重寫內置方法uncaughtException(Thread t,Throwable e)方法,里面寫自己的邏輯。(Tips:可以通過構造方法來傳模塊名字)

  然后,在需要配置的類中setDefaultUncaughtExceptionHandler(new HandlerInstance);


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

开封市| 遵化市| 刚察县| 乐都县| 抚远县| 承德县| 祥云县| 金阳县| 弋阳县| 成安县| 海南省| 鹤壁市| 凤城市| 泸西县| 托克托县| 都兰县| 郧西县| 闻喜县| 镇康县| 诏安县| 毕节市| 阿勒泰市| 金寨县| 韶关市| 墨玉县| 和静县| 宽城| 礼泉县| 类乌齐县| 广灵县| 离岛区| 渭南市| 陇西县| 黄陵县| 武陟县| 利辛县| 彭阳县| 枣阳市| 德清县| 麦盖提县| 独山县|