Java高並發編程(二),java並發編程

來源:互聯網
上載者:User

Java高並發編程(二),java並發編程
   一、高並發編程的幾個部分

  synchronized同步器、jdk提供的同步容器、ThreadPool線程池、executor執行器

  二、重入鎖

  1.reentrantlock關鍵字(相較於synchronized更加靈活)

  2.reentrantlock用於替代synchronized,在使用此鎖時必須要手動釋放鎖,在使用synchronized鎖時遇到異常時,jvm會自動釋放鎖,但是reentrantlock必須要手動釋放鎖,因此經常在finally中進行鎖的釋放

  Lock  lock = new Reentrantlock();//將參數設定為true時此鎖為公平鎖

  lock.lock();//相當於synchronized(this)

  lock.unlock();//開鎖

  3.使用reentrantlock可以進行嘗試鎖定“tryLock”,這樣在指定時間內無法鎖定,線程可決定是否繼續等待

  Boolean locked =lock.tryLock();

  if(locked)lock.unlock();

  先假定沒有得到鎖

  Boolean locked = false;

  try{

    locked = lock.tryLock(5,TimeUnit.SECONDS);//先嘗試等5秒

    //代碼邏輯,根據傳回值判斷

  }catch{

  }finally{

    if(locked)

      lock.unlock();//根據傳回值來判斷是否開鎖,如果已經得到鎖就開啟,未得到就不開

  }

  4.使用reentrantlock可以調用lockInterruptibly方法,可以相應interrupt方法作出響應(可被打斷方法),使用其他線程打斷當前線程等待

  5.reentrantlock還可以被指定為公平鎖,而synchronized為非公平鎖(非公平鎖的效率相對公平鎖來說較高)

    公平鎖:可以假定誰等待時間長誰獲得鎖

    非公平鎖:不考慮等待時間

  三、經典面試題

  生產者-消費者模式:寫一個固定容量的同步容器,擁有put和get方法,以及getCount方法,能夠支援兩個生產者線程以及是個消費者線程的阻塞調用

  同步容器:多個線程訪問不會出問題,容器滿了的話,調用put的線程需要等待,容器空了的話調用get的線程需要等待

  1.使用wait和notify/notifyAll來實現,wait99.9%的情況下與while一起使用,if是只判斷一次,while是每次要運行之前都進行判斷,不加notify的話可能會產生死結,假定當前等待線程為生產者線程,此時notify又喚醒一個生產者進程就造成了死結

public class MyContainer1<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10; //最多10個元素private int count = 0;public synchronized void put(T t) {while(lists.size() == MAX) { //想想為什麼用while而不是用if?try {this.wait(); //effective java} catch (InterruptedException e) {e.printStackTrace();}}lists.add(t);++count;this.notifyAll(); //通知消費者線程進行消費}public synchronized T get() {T t = null;while(lists.size() == 0) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}t = lists.removeFirst();count --;this.notifyAll(); //通知生產者進行生產return t;}public static void main(String[] args) {MyContainer1<String> c = new MyContainer1<>();//啟動消費者線程for(int i=0; i<10; i++) {new Thread(()->{for(int j=0; j<5; j++) System.out.println(c.get());}, "c" + i).start();}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}//啟動生產者線程for(int i=0; i<2; i++) {new Thread(()->{for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);}, "p" + i).start();}}}

  2.使用lock和Condition來實現,對比兩種方式,Condition的方式可以更加精確的指定哪些線程被喚醒

public class MyContainer2<T> {final private LinkedList<T> lists = new LinkedList<>();final private int MAX = 10; //最多10個元素private int count = 0;private Lock lock = new ReentrantLock();private Condition producer = lock.newCondition();private Condition consumer = lock.newCondition();public void put(T t) {try {lock.lock();while(lists.size() == MAX) { //想想為什麼用while而不是用if?producer.await();}lists.add(t);++count;consumer.signalAll(); //通知消費者線程進行消費} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public T get() {T t = null;try {lock.lock();while(lists.size() == 0) {consumer.await();}t = lists.removeFirst();count --;producer.signalAll(); //通知生產者進行生產} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}return t;}public static void main(String[] args) {MyContainer2<String> c = new MyContainer2<>();//啟動消費者線程for(int i=0; i<10; i++) {new Thread(()->{for(int j=0; j<5; j++) System.out.println(c.get());}, "c" + i).start();}try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}//啟動生產者線程for(int i=0; i<2; i++) {new Thread(()->{for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);}, "p" + i).start();}}}

  

  四、線程局部變數

  1.ThreadLocal關鍵字,線程局部變數

  2.線程局部變數之間互不影響,架構中大量使用,ThreadLocal使用空間換時間,而synchronized是使用時間換空間

public class ThreadLocal1 {/*volatile*/ static Person p = new Person();public static void main(String[] args) {new Thread(()->{try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(p.name);}).start();new Thread(()->{try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}p.name = "lisi";}).start();}}
public class ThreadLocal2 {//volatile static Person p = new Person();static ThreadLocal<Person> tl = new ThreadLocal<>();public static void main(String[] args) {new Thread(()->{try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(tl.get());}).start();new Thread(()->{try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}tl.set(new Person());}).start(); }static class Person {String name = "zhangsan";}}
  補充:

  整理出來的高並發編程比較基礎得知識點與面試題,如有不足也請指正,總之希望對大家有協助。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.