?
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 進程號