Java并發(fā)編程--基礎(chǔ)進階高級(完結(jié))

?

Java并發(fā)編程--基礎(chǔ)進階高級完整筆記。

這都不知道是第幾次刷狂神的JUC并發(fā)編程了,從第一次的迷茫到現(xiàn)在比較清晰,算是個大進步了,之前JUC筆記不見了,重新做一套筆記。

目錄

:fire:1.多線程--基礎(chǔ)內(nèi)容

:fire:2.八鎖現(xiàn)象(synchronized、static)

2.static synchronized

:fire:3.Java集合--安全性

:fire:4.高并發(fā)--輔助類

:fire:5.讀寫鎖(ReadWriteLock)

1.集合--隊列(阻塞隊列、同步隊列)

2.線程池基本概念(三大方法、七大參數(shù)、四種拒絕策略)

:fire:7.Stream(4個函數(shù)式接口、Lambda、異步回調(diào))

1.餓漢模式(程序一啟動就new,十分占內(nèi)存)

2.懶漢模式(DCL模式:雙重檢測,需要的時候才new)

:fire:9.Volatile和Atomic

1.公平鎖(FIFO):Lock鎖可以自定義,synchronized

2.非公平鎖(允許插隊):Lock鎖可以自定義

3.可重入鎖(獲取一個鎖再獲取其他鎖不會造成死鎖):lock鎖和synchronized

4.自旋鎖:得不到就一直等待(Atomic.getAndIncrement底層就是自旋鎖)

:fire:1.多線程--基礎(chǔ)內(nèi)容

1.Thread狀態(tài)

6種:新建、運行、阻塞、等待、超時等待、結(jié)束(可點擊Thread查看源代碼)

public enum State {

? ? ? ? NEW,

? ? ? ? RUNNABLE,

? ? ? ? BLOCKED,

? ? ? ? WAITING,

? ? ? ? TIMED_WAITING,

? ? ? ? TERMINATED;

? ? }

2.Synchronized

非公平鎖

可重入鎖,

Synchronized:是非公平鎖(不能保證線程獲得鎖的順序,即線程不會依次排隊去獲取資源,而是爭搶,但是結(jié)果一定是正確的),是可重入鎖(已獲得一個鎖,可以再獲得鎖且不會造成死鎖,比如synchronized內(nèi)部可以再寫個synchronized函數(shù))

/**

? ? * Author: HuYuQiao

? ? * Description: Synchronized實現(xiàn)方式(修飾函數(shù)即可)

? ? */

? ? class TicketSync{

? ? ? ? public int number = 50;

? ? ? ? //synchronized本質(zhì)是隊列,鎖

? ? ? ? public synchronized void sale(){

? ? ? ? ? ? if(number > 0) {

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "獲得了第" + number-- +"票");

? ? ? ? ? ? }

? ? ? ? }

? ? }

3.Lock鎖

可重入鎖

公平還是不公平鎖可以設(shè)置(默認不公平鎖)

/**

? ? * Creates an instance of {@code ReentrantLock} with the

? ? * given fairness policy.

? ? *

? ? * @param fair {@code true} if this lock should use a fair ordering policy

? ? */

? ? public ReentrantLock(boolean fair) {

? ? ? ? sync = fair ? new FairSync() : new NonfairSync();

? ? }

Lock:加鎖之后必須解鎖,,否則其他線程就獲取不到了,所以用try-catch-finally包起來。

/**

? ? * Author: HuYuQiao

? ? * Description: Lock實現(xiàn)方式(加鎖、解鎖)

? ? */

? ? class TicketLock{

? ? ? ? Lock lock = new ReentrantLock();

? ? ? ? public int number = 50;

? ? ? ? public void sale(){

? ? ? ? ? ? lock.lock();

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "獲得了第" + number-- +"票");

? ? ? ? ? ? } catch (Exception e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? } finally {

? ? ? ? ? ? ? ? lock.unlock();

? ? ? ? ? ? }

? ? ? ? }

? ? }

4.總結(jié)

在不加鎖情況下,多線程會爭搶,導致輸出順序、計算結(jié)果都會不一致(上面例子結(jié)果如果一樣是因為只有3個線程,for循環(huán)即出錯,因為number--這個函數(shù)本身不是線程安全的),所以就引入了鎖的概念,synchronized,lock保證了輸出順序、計算結(jié)果的一致性。

虛假喚醒:在synchronized.wait與lock.condition.await喚醒線程時,是從await代碼之后開始運行,所以為了保證能喚醒線程,需要用while語句將代碼包含起來。

完整代碼

package com.empirefree.springboot;

import lombok.extern.slf4j.Slf4j;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit4.SpringRunner;

import sun.security.krb5.internal.Ticket;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/**

* @program: springboot

* @description: 多線程

* @author: huyuqiao

* @create: 2021/06/26 14:26

*/

@RunWith(SpringRunner.class)

@SpringBootTest

@Slf4j

public class ThreadTest {


? ? /**

? ? * Author: HuYuQiao

? ? * Description: Synchronized實現(xiàn)方式(修飾函數(shù)即可)

? ? */

? ? class TicketSync{

? ? ? ? public int number = 50;

? ? ? ? //synchronized本質(zhì)是隊列,鎖

? ? ? ? public synchronized void sale(){

? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "獲得了第" + number-- +"票");

? ? ? ? }

? ? }


? ? /**

? ? * Author: HuYuQiao

? ? * Description: Lock實現(xiàn)方式(加鎖、解鎖)

? ? */

? ? class TicketLock{

? ? ? ? Lock lock = new ReentrantLock();

? ? ? ? public int number = 50;

? ? ? ? public void sale(){

? ? ? ? ? ? lock.lock();

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "獲得了第" + number-- +"票");

? ? ? ? ? ? } catch (Exception e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? } finally {

? ? ? ? ? ? ? ? lock.unlock();

? ? ? ? ? ? }

? ? ? ? }

? ? }

? ? @Test

? ? public void testThread() {

//? ? ? ? TicketSync ticket = new TicketSync();

? ? ? ? TicketLock ticket = new TicketLock();

? ? ? ? new Thread( () ->{

? ? ? ? ? ? for (int i = 0; i < 50; i++) {

? ? ? ? ? ? ? ? ticket.sale();

? ? ? ? ? ? }

? ? ? ? },"ThreadA").start();

? ? ? ? new Thread(()->{

? ? ? ? ? ? for (int i = 0; i < 50; i++) {

? ? ? ? ? ? ? ? ticket.sale();

? ? ? ? ? ? }

? ? ? ? },"ThreadB").start();

? ? ? ? new Thread(()->{

? ? ? ? ? ? for (int i = 0; i < 50; i++) {

? ? ? ? ? ? ? ? ticket.sale();

? ? ? ? ? ? }

? ? ? ? },"ThreadC").start();

? ? ? ? for (int i = 0; i < 500; i++) {

? ? ? ? ? ? new Thread(() -> {

? ? ? ? ? ? ? ? ticket.sale();

? ? ? ? ? ? }).start();

? ? ? ? }

? ? }

}

:fire:2.八鎖現(xiàn)象(synchronized、static)

即synchronized、static修飾的函數(shù),執(zhí)行順序、輸出結(jié)果。

結(jié)果表明:

1.synchronized修飾的函數(shù):會鎖住對象(可以看成鎖對象中某個方法),看起來代碼會依次執(zhí)行,而沒有鎖的方法即不受影響,一來就先執(zhí)行

2.static synchronized修飾的函數(shù):會鎖住類.class(可以不同對象訪問的都是同一個函數(shù)),所以2個對象訪問自己的函數(shù)依然還是順序執(zhí)行.

3.一個有static,一個沒有static:即一個鎖類.class,另一個鎖對象,不管是同一個對象還是不同對象,就都不需要等待了,不會順序執(zhí)行。

1.synchronized

修飾函數(shù)會保證同一對象依次順序執(zhí)行()

class Phone{

? ? //synchronized

? ? public synchronized void sendSms() {

? ? ? ? try {

? ? ? ? ? ? TimeUnit.SECONDS.sleep(4);

? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? System.out.println("sendSms");

? ? }

? ? public synchronized? void call() {

? ? ? ? System.out.println("call");

? ? }

? ? public void playGame(){

? ? ? ? System.out.println("playGame");

? ? }

}

? ? public static void main(String[] args) {

? ? ? ? //Thread--代碼執(zhí)行順序問題

? ? ? ? Phone phone = new Phone();

? ? ? ? new Thread(phone::sendSms, "A").start();

? ? ? ? try {

? ? ? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? new Thread(phone::call, "B").start();

? ? ? ? new Thread(phone::playGame, "C").start();

? ? }

2.static synchronized

class PhoneStatic{

? ? //static synchronized

? ? public static synchronized void sendSmsStatic() {

? ? ? ? try {

? ? ? ? ? ? TimeUnit.SECONDS.sleep(4);

? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? System.out.println("sendSmsStatic");

? ? }

? ? public static synchronized? void callStatic() {

? ? ? ? System.out.println("callStatic");

? ? }

}

? ? public static void main(String[] args) {

? ? ? ? PhoneStatic phoneStatic = new PhoneStatic();

? ? ? ? PhoneStatic phoneStatic2 = new PhoneStatic();

? ? ? ? new Thread(() ->{

? ? ? ? ? ? phoneStatic2.sendSmsStatic();

? ? ? ? }, "A").start();

? ? ? ? try {

? ? ? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? new Thread(() ->{

? ? ? ? ? ? phoneStatic2.callStatic();

? ? ? ? }, "B").start();

? ? }

:fire:3.Java集合--安全性

//集合安全性--list,set,map都非線程安全

? ? ? ? List<String> list = new Vector<>();

? ? ? ? List<String> list = Collections.synchronizedList(new ArrayList<>());

? ? ? ? List<String> list = new CopyOnWriteArrayList<>();

? ? ? ? Map<String, String> objectObjectHashMap = new ConcurrentHashMap<>();

? ? ? ? Map<Object, Object> objectObjectHashMap1 = Collections.synchronizedMap(new HashMap<>());

? ? ? ? //set底層就是map:無論hashset還是linkedhashset

? ? ? ? Set<String> set = Collections.synchronizedSet(new LinkedHashSet<>());

? ? ? ? Set<String> set = new CopyOnWriteArraySet<>();

:fire:4.高并發(fā)--輔助類

1.countdownLatch

Countdownlatch:減一操作,直到為0再繼續(xù)向下執(zhí)行

package Kuangshen.JUC.Thread;

import java.util.concurrent.CountDownLatch;

public class countDownLatch {

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

? ? ? ? final CountDownLatch countDownLatch = new CountDownLatch(5);

? ? ? ? for (int i = 0; i < 5; i++) {

? ? ? ? ? ? new Thread(() -> {

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

? ? ? ? ? ? ? ? countDownLatch.countDown();

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

? ? ? ? }

? ? ? ? countDownLatch.await(); //等待上述執(zhí)行完畢再向下執(zhí)行

? ? ? ? System.out.println("close door");

? ? }

}

2.cyclicbarrier

Cyclicbarrier:+1操作,對于每個線程都自動+1并等待,累計到規(guī)定值再向下執(zhí)行,

package Kuangshen.JUC.Thread;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

/**

* @author :Empirefree

* @description:TODO

* @date :2021/2/10 10:56

*/

public class cyclicbarrier {

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

? ? ? ? //CyclicBarrier里面是容量 + runnable

? ? ? ? final CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () ->{

? ? ? ? ? ? System.out.println("不斷增加到7即向后執(zhí)行,與countdownlatch相反");

? ? ? ? }

? ? ? );

? ? ? ? /*對于指派的局部變量,lambda只能捕獲一次 ,故而需定義成final(int內(nèi)部定義就是final),而且線程中,

? ? ? ? 不能對局部變量進行修改,如需要修改,需定義成原子類atomic

? ? ? ? */

? ? ? ? for (int i = 0; i < 7; i++) {

? ? ? ? ? ? int finalI = i;

? ? ? ? ? ? new Thread(() ->{

? ? ? ? ? ? ? ? System.out.println(finalI);

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? cyclicBarrier.await();

? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? } catch (BrokenBarrierException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }).start();

? ? ? ? }

? ? }

}

3.semaphore

semaphore:對于規(guī)定的值,多個線程只規(guī)定有指定的值能獲取,每次獲取都需要最終釋放,保證一定能互斥執(zhí)行

package Kuangshen.JUC.Thread;

import java.util.concurrent.Semaphore;

import java.util.concurrent.TimeUnit;

/**

* @author :Empirefree

* @description:TODO

* @date :2021/2/10 15:24

*/

public class semaphore {

? ? public static void main(String[] args) {

? ? ? ? final Semaphore semaphore = new Semaphore(3);

? ? ? ? for (int i = 0; i < 60; i++) {

? ? ? ? ? ? new Thread(() -> {

? ? ? ? ? ? ? ? try {

? ? ? ? ? ? ? ? ? ? semaphore.acquire();

? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "搶到車位");

? ? ? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(2);

? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName() + "離開車位");

? ? ? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? ? ? } finally {

? ? ? ? ? ? ? ? ? ? semaphore.release();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }).start();

? ? ? ? }

? ? }

}

:fire:5.讀寫鎖(ReadWriteLock)

ReadWriteLock也是多線程下的一種加鎖方式,下面列出ReadWriteLock和synchronized對多線程下,保證讀完之后在寫的實現(xiàn)方式

//讀寫鎖 :寫只有一個線程寫,寫完畢后 可以多個線程讀

MyCache myCache = new MyCache();

int num = 6;

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

? ? int finalI = i;

? ? new Thread(()->{

? ? ? ? myCache.write(String.valueOf(finalI),String.valueOf(finalI));

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

}

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

? ? int finalI = i;

? ? new Thread(()->{

? ? ? ? myCache.read(String.valueOf(finalI));

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

}

class MyCache{

? ? private volatile Map<String,String> map = new HashMap<>();

? ? private ReadWriteLock lock = new ReentrantReadWriteLock();

? ? //存,寫

? ? public void write(String key,String value){

? ? ? ? lock.writeLock().lock();? ? //寫鎖

? ? ? ? try {

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程開始寫入");

? ? ? ? ? ? map.put(key,value);

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程開始寫入ok");

? ? ? ? } catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } finally {

? ? ? ? ? ? lock.writeLock().unlock();

? ? ? ? }

? ? }

? ? //取,讀

? ? public void read(String key){

? ? ? ? lock.readLock().lock();? ? //讀鎖

? ? ? ? try {

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程開始讀取");

? ? ? ? ? ? map.get(key);

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程讀取ok");

? ? ? ? } catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? } finally {

? ? ? ? ? ? lock.readLock().unlock();

? ? ? ? }

? ? }

? ? //存,寫

? ? public synchronized void writeSync(String key,String value){

? ? ? ? try {

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程開始寫入");

? ? ? ? ? ? map.put(key,value);

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程開始寫入ok");

? ? ? ? } catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

? ? //取,讀

? ? public void readSync(String key){

? ? ? ? try {

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程開始讀取");

? ? ? ? ? ? map.get(key);

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"線程讀取ok");

? ? ? ? } catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

}

:fire:6.線程池

1.集合--隊列(阻塞隊列、同步隊列)

阻塞隊列:blockingQueue(超時等待--拋棄,所以最后size=1)

//阻塞隊列

? ? ? ? ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);

? ? ? ? arrayBlockingQueue.offer("a", 2, TimeUnit.SECONDS);

? ? ? ? arrayBlockingQueue.offer("a", 2, TimeUnit.SECONDS);

? ? ? ? System.out.println("超時等待==" + arrayBlockingQueue.size());

同步隊列:synchronizeQueue(類似于生產(chǎn)者消費者)

//同步隊列

? ? ? ? SynchronousQueue<String> synchronousQueue = new SynchronousQueue<>();

? ? ? ? new Thread(()->{

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"put 01");

? ? ? ? ? ? ? ? synchronousQueue.put("1");

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"put 02");

? ? ? ? ? ? ? ? synchronousQueue.put("2");

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"put 03");

? ? ? ? ? ? ? ? synchronousQueue.put("3");

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? }).start();

? ? ? ? new Thread(()->{

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"take"+synchronousQueue.take());

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"take"+synchronousQueue.take());

? ? ? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+"take"+synchronousQueue.take());

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? }).start();

2.線程池基本概念(三大方法、七大參數(shù)、四種拒絕策略)

三大方法:newSingleThreadExecutro(單個線程),newFixedThreadPool(固定大小線程池),newCachedThreadPool(可伸縮)

ExecutorService threadPool = Executors.newSingleThreadExecutor();

? ? ? ? ExecutorService threadPool2 = Executors.newFixedThreadPool(5);

? ? ? ? ExecutorService threadPool3 = Executors.newCachedThreadPool();

七大參數(shù):

ThreadPoolExecutor(int corePoolSize,? //核心線程池大小

? ? ? ? ? ? ? ? ? ? ? ? ? int maximumPoolSize, //最大的線程池大小(當阻塞隊列滿了就會打開)

? ? ? ? ? ? ? ? ? ? ? ? ? long keepAliveTime,? //(空閑線程最大存活時間:即最大線程池中有空閑線程超過這個時間就會釋放線程,避免資源浪費)

? ? ? ? ? ? ? ? ? ? ? ? ? TimeUnit unit, //超時單位

? ? ? ? ? ? ? ? ? ? ? ? ? BlockingQueue<Runnable> workQueue, //阻塞隊列

? ? ? ? ? ? ? ? ? ? ? ? ? ThreadFactory threadFactory, //線程工廠 創(chuàng)建線程的 一般不用動

? ? ? ? ? ? ? ? ? ? ? ? ? RejectedExecutionHandler handler //拒絕策略

四種拒絕策略:

new ThreadPoolExecutor.AbortPolicy: // 該 拒絕策略為:銀行滿了,還有人進來,不處理這個人的,并拋出異常

new ThreadPoolExecutor.CallerRunsPolicy(): // //該拒絕策略為:哪來的去哪里 main線程進行處理

new ThreadPoolExecutor.DiscardPolicy(): //該拒絕策略為:隊列滿了,丟掉異常,不會拋出異常。

new ThreadPoolExecutor.DiscardOldestPolicy(): //該拒絕策略為:隊列滿了,嘗試去和最早的進程競爭,不會拋出異常

//異步回調(diào)--無返回值

? ? ? ? CompletableFuture<Void> future = CompletableFuture.runAsync(() ->{

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(2);

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

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

? ? ? ? });

? ? ? ? System.out.println("begin");

? ? ? ? System.out.println(future.get());

? ? ? ? System.out.println("end");

? ? ? ? //異步回調(diào)--有返回值

? ? ? ? CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() ->{

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(2);

? ? ? ? ? ? } catch (InterruptedException e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? }

? ? ? ? ? ? return 3;

? ? ? ? });

? ? ? ? System.out.println("begin");

? ? ? ? System.out.println(future2.get());

? ? ? ? System.out.println(future2.whenComplete((result, error) ->{

? ? ? ? ? ? System.out.println("返回結(jié)果:" + result);

? ? ? ? ? ? System.out.println("錯誤結(jié)果" + error);

? ? ? ? }).exceptionally(throwable -> {

? ? ? ? ? ? System.out.println(throwable.getMessage());

? ? ? ? ? ? return 502;

? ? ? ? }).get());

? ? ? ? System.out.println("end");

:fire:8.單例模式

1.餓漢模式(程序一啟動就new,十分占內(nèi)存)

/**

* @program: untitled

* @description: 單例模式

* @author: huyuqiao

* @create: 2021/06/27 14:44

*/

public class SingleModel {

? ? /*

? ? * 可能會浪費空間

? ? * */

? ? private byte[] data1 = new byte[1024*1024];

? ? private byte[] data2 = new byte[1024*1024];

? ? private byte[] data3 = new byte[1024*1024];

? ? private byte[] data4 = new byte[1024*1024];

? ? private static final SingleModel hugrySingle = new SingleModel();

? ? private SingleModel(){

? ? }

? ? public static SingleModel getInstance(){

? ? ? ? return hugrySingle;

? ? }

}

2.懶漢模式(DCL模式:雙重檢測,需要的時候才new)

1.第一層if沒有加鎖,所以會有多個線程到達if

2.如果內(nèi)部new對象指令重排,就會導致有些線程認為lazyManModel有對象,所以會直接返回lazyManModel(實際為null)

3.所以需要加上valitile防止指令重排

/**

* @program: untitled

* @description: 懶漢式

* @author: huyuqiao

* @create: 2021/06/27 15:06

*/

public class LazyManModel {

? ? private volatile static LazyManModel lazyManModel;

? ? private LazyManModel(){

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

? ? }

? ? //DCL懶漢式:雙重檢測鎖--實現(xiàn)效果,只有為空的才null,否則不用null,所以需要2重if判斷。

? ? public static LazyManModel getInstance(){

? ? ? ? if (lazyManModel == null){

? ? ? ? ? ? synchronized (LazyManModel.class){

? ? ? ? ? ? ? ? if (lazyManModel == null){

? ? ? ? ? ? ? ? ? ? lazyManModel = new LazyManModel();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return lazyManModel;

? ? }

? ? public static void main(String[] args) {

? ? ? ? for (int i = 0; i < 10; i++) {

? ? ? ? ? ? new Thread(() ->{

? ? ? ? ? ? ? ? LazyManModel.getInstance();

? ? ? ? ? ? }).start();

? ? ? ? }

? ? }

}

:fire:9.Volatile和Atomic

如果感覺小編寫得不錯,請素質(zhì)三連:點贊+轉(zhuǎn)發(fā)+關(guān)注。我會努力寫出更好的作品分享給大家。更多學習資料小編已打包好,可以找我領(lǐng)取哦!領(lǐng)取方式:私信回復暗號【444】即可免費領(lǐng)取更多完整版資料。

:fire:10.Java中鎖

1.公平鎖(FIFO):Lock鎖可以自定義,synchronized

2.非公平鎖(允許插隊):Lock鎖可以自定義

3.可重入鎖(獲取一個鎖再獲取其他鎖不會造成死鎖):lock鎖和synchronized

4.自旋鎖:得不到就一直等待(Atomic.getAndIncrement底層就是自旋鎖)

import java.util.Collections;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicInteger;

import java.util.concurrent.atomic.AtomicReference;

import java.util.concurrent.locks.ReentrantLock;

/**

* @program: untitled

* @description: spinlock

* @author: huyuqiao

* @create: 2021/06/27 15:40

*/

public class SpinLockTest {

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

? ? ? ? //使用CAS實現(xiàn)自旋鎖

? ? ? ? SpinlockDemo spinlockDemo=new SpinlockDemo();

? ? ? ? new Thread(()->{

? ? ? ? ? ? spinlockDemo.myLock();

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(3);

? ? ? ? ? ? } catch (Exception e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? } finally {

? ? ? ? ? ? ? ? spinlockDemo.myUnlock();

? ? ? ? ? ? }

? ? ? ? },"t1").start();

? ? ? ? TimeUnit.SECONDS.sleep(1);

? ? ? ? new Thread(()->{

? ? ? ? ? ? spinlockDemo.myLock();

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? TimeUnit.SECONDS.sleep(3);

? ? ? ? ? ? } catch (Exception e) {

? ? ? ? ? ? ? ? e.printStackTrace();

? ? ? ? ? ? } finally {

? ? ? ? ? ? ? ? spinlockDemo.myUnlock();

? ? ? ? ? ? }

? ? ? ? },"t2").start();

? ? }

}

class SpinlockDemo {

? ? // 默認

? ? // int 0

? ? //thread null

? ? AtomicReference<Thread> atomicReference=new AtomicReference<>();

? ? //加鎖

? ? public void myLock(){

? ? ? ? Thread thread = Thread.currentThread();

? ? ? ? System.out.println(thread.getName()+"===> mylock");

? ? ? ? //自旋鎖--為空則返回true,否則返回false

? ? ? ? while (!atomicReference.compareAndSet(null,thread)){

? ? ? ? ? ? System.out.println(Thread.currentThread().getName()+" ==> .自旋中~");

? ? ? ? }

? ? }

? ? //解鎖

? ? public void myUnlock(){

? ? ? ? Thread thread=Thread.currentThread();

? ? ? ? System.out.println(thread.getName()+"===> myUnlock");

? ? ? ? atomicReference.compareAndSet(thread,null);

? ? }

}

5.死鎖命令排查

jps -l

jstack 進程號

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容