一、原子引用java
package com.example.mybaties; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; import java.util.concurrent.atomic.AtomicReference; /** * @DESCRIPTION 原子引用 * @Author lst * @Date 2020-03-24 09:00 */ public class AtomicReferenceDemo { public static void main(String[] args) { User z3 = new User("z3",22); User li4 = new User("li4",25); AtomicReference<User> atomicReference = new AtomicReference(); atomicReference.set(z3); System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString()); System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());//主物理內存已經變成li4 /** * true User(userName=li4, age=25) * false User(userName=li4, age=25) */ } } @Getter @ToString @AllArgsConstructor class User { String userName; int age; }
二、可重入鎖api
package com.example.mybaties; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @DESCRIPTION 可重入鎖(也叫遞歸鎖) * 指的是同一線程外層脳數得到鎖以後,內層遞歸數仍然能獲取該鎖的代嗎,在同一個線程在外層方法英取的時候, * 在進入內層方法會自動獲取鎖也便是說,線程能夠進入一個任何它已經擁有的所同歩的代碼塊 * * * 就是一個典型的可重入鎖 * * 11invoked sendSms * 11#######invoked sendEmail * 12invoked sendSms * 12#######invoked sendEmail * * * * @Author lst * @Date 2020-03-23 14:48 */ class Phone implements Runnable{ public synchronized void sendSms(){ System.out.println(Thread.currentThread().getId() + "invoked sendSms "); sendEmail(); } public synchronized void sendEmail(){ System.out.println(Thread.currentThread().getId() + "#######invoked sendEmail "); } Lock lock = new ReentrantLock();//默認非公平鎖 @Override public void run() { get(); } public void get(){ lock.lock(); lock.lock(); System.out.println(Thread.currentThread().getName() + " invoked get() "); set(); lock.unlock(); lock.unlock(); } public void set(){ lock.lock(); System.out.println(Thread.currentThread().getName() + " ####invoked set() "); lock.unlock(); } } public class ReenterLockDemo { public static void main(String[] args) { Phone phone = new Phone(); new Thread(() -> { phone.sendSms(); },"t1").start(); new Thread(() -> { phone.sendSms(); },"t2").start(); //暫停一會 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(); System.out.println(); System.out.println(); System.out.println(); System.out.println(); Thread t3 = new Thread(phone,"t3"); Thread t4 = new Thread(phone,"t4"); t3.start(); t4.start(); /** * 14invoked sendSms * 14#######invoked sendEmail * 13invoked sendSms * 13#######invoked sendEmail * * * * * * t3 invoked get() * t3 ####invoked set() * t4 invoked get() * t4 ####invoked set() */ } }
三、讀寫鎖多線程
/** * @DESCRIPTION 讀寫鎖 *多個線程同時讀一個資源關沒有任何問題,因此爲了知足併發量,讀取共享資源應該能夠同時進行 * 可是若是有一個線程想去寫共享資源來,就不該該再有其它線程能夠對該資源進行讀或寫 * 小總結 * 讀-讀能共存 * 讀-寫不能共存 * 寫不能共存 * * * 寫操做:原子(完整一致性)+獨佔,整個過程必須是一個完整的統一體,中間不能間斷 * * @Author lst * @Date 2020-03-24 12:00 */ class MyCache { //資源類 private volatile Map<String,Object> map = new HashMap<>(); private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); public void put(String key,Object value){ //寫鎖 rwLock.writeLock().lock(); try { System.out.println(Thread.currentThread().getName()+" 正在寫入: " +key); //暫停一會線程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } map.put(key,value); System.out.println(Thread.currentThread().getName()+" 寫入完成: " ); }catch (Exception e){ e.getMessage(); }finally { rwLock.writeLock().unlock(); } } public void get(String key){ //讀鎖 rwLock.readLock().lock(); try { System.out.println(Thread.currentThread().getName()+" 正在讀取: " +key); //暫停一會線程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } Object result = map.get(key); System.out.println(Thread.currentThread().getName()+" 讀取完成: " + result); }catch (Exception e){ e.getMessage(); }finally { rwLock.readLock().unlock(); } } public void clearMap(){ map.clear(); } } public class ReentranRreadWriteLockDemo { public static void main(String[] args) { MyCache myCache = new MyCache(); for (int i = 0; i < 5; i++) { final String keyValue = String.valueOf(i); new Thread(() -> { myCache.put(keyValue,keyValue); },keyValue).start(); } for (int i = 0; i < 5; i++) { final String keyValue = String.valueOf(i); new Thread(() -> { myCache.get(keyValue); },keyValue).start(); } /* 0 正在寫入: 0 0 寫入完成: 1 正在寫入: 1 1 寫入完成: 2 正在寫入: 2 2 寫入完成: 3 正在寫入: 3 3 寫入完成: 4 正在寫入: 4 4 寫入完成: 0 正在讀取: 0 1 正在讀取: 1 2 正在讀取: 2 3 正在讀取: 3 4 正在讀取: 4 0 讀取完成: 0 1 讀取完成: 1 2 讀取完成: 2 3 讀取完成: 3 4 讀取完成: 4 */ ShareResource shareResource = new ShareResource(); new Thread(() -> { for (int i = 1; i <= 10; i++) { shareResource.print5(); } },"A").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { shareResource.print10(); } },"B").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { shareResource.print15(); } },"C").start(); } }
四、synchronized和lock有什麼區別?用新的lock有什麼好處?你挙例說說併發
/** * 題目: synchronized 和lock有什麼區別?用新的lock有什麼好處?你挙例說說 * 一、原始構成 * synchronized是關字jvm層面, * monitorenter(底層是經過monitor對象來完成,其實wait/ notify等方法也依 monitor對象只有在同步塊或方法中能源ait/ notify等方 * monitorexit * Lock是具體類(java,utiL, concurrent. Locks.Lock)是api層面的鎖 * 二、使用方法 * synchronized 不須要用戶去手動釋放鎖,當 synchronized代碼執行完後系統會自動讓線程釋放對鎖的佔用 * Reentrantlock則須要戶去手動釋放鎖,若沒有主動釋放鎖,就有可能致使出現死鎖現象。須要Lock()和unLock()方法配合try/ finally語句塊來完成 * 三、等待是否可中斷 * synchronized 不可中斷,除非拋出異常或者正常運行完成 * Reentrantlock 可中斷, * 1.設置超時方法 trylock( long timeout, Timeunit unit) * 2. LockInterruptibly()放代碼塊中,調 interrupt()方法可中斷 * 四、加鎖是否公平 * synchronized非公平鎖 * Reentrantlock 二者均可以,默認非公平鎖,構造方法能夠傳入 boolean值,true爲公平鎖, false爲非公平鎖 * * 五、鎖綁定多個條件 Condition * synchronized沒有 * Reentrantlock,用來實分組喚要喚的線程,能夠精確喚醒,而不是像 synchronized要麼隨機喚醒一個線程 要麼喚醒所有線程 * * * 原始構成:synchronized是JVM層面的,底層經過monitorenter和monitorexit來實現的。Lock是JDK API層面的。(synchronized一個enter會有兩個exit,一個是正常退出,一個是異常退出(保證確定能夠退出)) * 使用方法:synchronized不須要手動釋放鎖,而Lock須要手動釋放。 * 是否可中斷:synchronized不可中斷,除非拋出異常或者正常運行完成。Lock是可中斷的,1.設置超時方法tryLock(long timeout,TimeUnit unit); 2. lockInterruptibly()方法放代碼塊中,調用interrupt() * 是否爲公平鎖:synchronized只能是非公平鎖,而ReentrantLock既能是公平鎖,又能是非公平鎖,構造方法傳入false/true,默認是非公平鎖false。 * 綁定多個條件:synchronized不能,只能隨機喚醒。而Lock能夠經過Condition來綁定多個條件,精確喚醒。 * * * 題目:多線程之按順序調用,實現A->B->C三個線程啓動,要求以下 * AA打印5次,BB打印10次,CC打印15次 * 緊接着 * AA打印5次,BB打印10次,CC打印15次 * 。。。。。。 * 來10輪 * */ class ShareResource{ private int number = 1;//A:1 B:2 C:3 private Lock lock = new ReentrantLock(); private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); public void print5(){ lock.lock(); try{ //一、判斷 while (number != 1){ c1.await(); } //二、幹活 for (int i = 1; i <= 5 ; i++) { System.out.println(Thread.currentThread().getName()+" " + i); } //三、通知 number = 2; c2.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void print10(){ lock.lock(); try{ //一、判斷 while (number != 2){ c2.await(); } //二、幹活 for (int i = 1; i <= 10 ; i++) { System.out.println(Thread.currentThread().getName()+" " + i); } //三、通知 number = 3; c3.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void print15(){ lock.lock(); try{ //一、判斷 while (number != 3){ c3.await(); } //二、幹活 for (int i = 1; i <= 15 ; i++) { System.out.println(Thread.currentThread().getName()+" " + i); } //三、通知 number = 1; c3.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } }