因为内容太多了,所以将其拆分为以下内容
参考
https://www.bilibili.com/video/BV1B7411L7tE
彻底玩转单例模式
饿汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Hungry { 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 Hungry () { } private final static Hungry HUNGRY=new Hungry (); private static Hungry getInstance () { return HUNGRY; } public static void main (String[] args) { } }
DCL懒汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public class LazyMan { private static boolean flag = false ; private LazyMan () { synchronized (LazyMan.class) { if (flag == false ) { flag = true ; } else { throw new RuntimeException ("不要试图利用反射破坏异常" ); } } } private volatile static LazyMan lazyMan; public static LazyMan getInstance () { if (lazyMan == null ) { synchronized (LazyMan.class) { if (lazyMan == null ) { lazyMan = new LazyMan (); } } } return lazyMan; } public static void main (String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null ); declaredConstructor.setAccessible(true ); LazyMan instance2 = declaredConstructor.newInstance(); LazyMan instance3 = declaredConstructor.newInstance(); System.out.println(instance2); System.out.println(instance3); } }
静态内部类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Holder { private Holder () { } public static Holder getInstance () { return InnerClass.HOLDER; } public static class InnerClass { private final static Holder HOLDER = new Holder (); } }
单例不安全,反射
枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public enum EnumSingle { INSTANCE; public EnumSingle getInstance () { return INSTANCE; } } class Test { public static void main (String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { EnumSingle instance1 = EnumSingle.INSTANCE; Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null ); declaredConstructor.setAccessible(true ); EnumSingle instance2=declaredConstructor.newInstance(); System.out.println(instance1); System.out.println(instance2); } }
枚举的最终反编译,源码有的是有参构造
深入理解CAS
什么是 CAS
大厂必须要研究底层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class CASDemo { public static void main (String[] args) { AtomicInteger atomicInteger=new AtomicInteger (2020 ); System.out.println(atomicInteger.compareAndSet(2020 , 2021 )); System.out.println(atomicInteger.get()); System.out.println(atomicInteger.compareAndSet(2020 , 2021 )); System.out.println(atomicInteger.get()); } }
Unsafe 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class AtomicInteger extends Number implements java .io.Serializable { private static final long serialVersionUID = 6214790243416807050L ; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value" )); } catch (Exception ex) { throw new Error (ex); } } private volatile int value; ... }
1 public final native boolean compareAndSwapInt (Object var1, long var2, int var4, int var5) ;
1 2 3 4 5 6 7 8 public final int getAndAddInt (Object var1, long var2, int var4) { int var5; do { var5 = this .getIntVolatile(var1, var2); } while (!this .compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
CAS
比较并交换,比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作!如果不是就一直循环!
缺点:
循环会耗时
一次性只能保证一个共享交量的原子性
ABA问题
CAS : ABA 问题(狸猫换太子)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class CASDemo { public static void main (String[] args) { AtomicInteger atomicInteger = new AtomicInteger (2020 ); System.out.println(atomicInteger.compareAndSet(2020 , 2021 )); System.out.println(atomicInteger.get()); System.out.println(atomicInteger.compareAndSet(2021 , 2020 )); System.out.println(atomicInteger.get()); System.out.println(atomicInteger.compareAndSet(2020 , 2021 )); System.out.println(atomicjavaInteger.get()); } }
原子引用
解决 ABA 问题,引入原子引用!对应思想:乐观锁!
带版本号的 原子操作!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class CASDemo { public static void main (String[] args) { AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference <>(1 ,1 ); new Thread (()->{ int stamp = atomicInteger.getStamp(); System.out.println("A1=> " +stamp); try { TimeUnit.SECONDS.sleep(1 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(atomicInteger.compareAndSet(1 , 2 , atomicInteger.getStamp(), atomicInteger.getStamp() + 1 )); System.out.println("A2=> " +atomicInteger.getStamp()); System.out.println(atomicInteger.compareAndSet(2 , 1 , atomicInteger.getStamp(), atomicInteger.getStamp() + 1 )); System.out.println("A3=> " +atomicInteger.getStamp()); },"A" ).start(); new Thread (()->{ int stamp = atomicInteger.getStamp(); System.out.println("B1=> " +stamp); try { TimeUnit.SECONDS.sleep(2 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(atomicInteger.compareAndSet(1 , 6 , stamp, stamp + 1 )); java System.out.println("B2=> " +atomicInteger.getStamp()); },"B" ).start(); } }
注意:
【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals
方法比较。 说明:对于 Integer var = ? 在-128 至 127
范围内的赋值,Integer 对象是在 阿里巴巴 Java 开发手册
——禁止用于商业用途,违者必究—— 7 /35 IntegerCache.cache
产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行
判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,
推荐使用 equals 方法进行判断。 ---《阿里巴巴Java开发手册》
各种锁的理解
公平锁、非公平锁
公平锁:非常公平,不能够插队,必须先来后到!
非公平锁:非常不公平,可以插队(默认都是非公平)
1 2 3 4 5 6 7 public ReentrantLock () { sync = new NonfairSync (); } public ReentrantLock (boolean fair) { sync = fair ? new FairSync () : new NonfairSync (); }
可重用锁
可重用锁(递归锁)
Synchronized
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class Demo1 { public static void main (String[] args) { Phone1 phone = new Phone1 (); new Thread (() -> { phone.sms(); },"A" ).start(); new Thread (() -> { phone.sms(); },"B" ).start(); } } class Phone1 { public synchronized void sms () { System.out.println(Thread.currentThread().getName() + " sms" ); call(); } public synchronized void call () { System.out.println(Thread.currentThread().getName() + " call" ); } }
Lock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public class Demo2 { public static void main (String[] args) { Phone2 phone = new Phone2 (); new Thread (() -> { phone.sms(); }, "A" ).start(); new Thread (() -> { phone.sms(); }, "B" ).start(); } } class Phone2 { Lock lock = new ReentrantLock (); public synchronized void sms () { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " sms" ); call(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public synchronized void call () { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " call" ); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
自旋锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class SpinLockDemo { AtomicReference<Thread> atomicReference=new AtomicReference <>(); public void myLock () { Thread thread=Thread.currentThread(); System.out.println(Thread.currentThread().getName()+"==> mylock" ); while (!atomicReference.compareAndSet(null ,thread)){ } } public void myUnLock () { Thread thread=Thread.currentThread(); System.out.println(Thread.currentThread().getName()+"==> myUnlock" ); atomicReference.compareAndSet(thread,null ); } }
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class TestSpinLock { public static void main (String[] args) { SpinLockDemo lock = new SpinLockDemo (); new Thread (() -> { lock.myLock(); try { TimeUnit.SECONDS.sleep(3 ); } catch (Exception e) { } finally { lock.myUnLock(); } }, "T1" ).start(); new Thread (() -> { lock.myLock(); try { TimeUnit.SECONDS.sleep(1 ); } catch (Exception e) { } finally { lock.myUnLock(); } }, "T2" ).start(); } }
死锁
死锁是什么
死锁测试,怎么排除死锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class DeadLockDemo { public static void main (String[] args) { String lockA="lockA" ; String lockB="lockB" ; new Thread (new MyThread (lockA,lockB),"T1" ).start(); new Thread (new MyThread (lockB,lockA),"T2" ).start(); } } class MyThread implements Runnable { private String lockA; private String lockB; public MyThread (String lockA,String lockB) { this .lockA=lockA; this .lockB=lockB; } @Override public void run () { synchronized (lockA){ System.out.println(Thread.currentThread().getName()+"lock:" +lockA+"=>get" +lockB); try { TimeUnit.SECONDS.sleep(2 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lockB){ System.out.println(Thread.currentThread().getName()+"lock:" +lockB+"=>get" +lockA); } } } }
解决问题
1、使用 jps
定位进程号
1 2 3 4 5 6 7 C:\Users\18339\Desktop\ideaprojects\juc>jps -l 15792 com.lock.DeadLockDemo 9504 org.jetbrains.jps.cmdline.Launcher 14868 sun.tools.jps.Jps 9512 C:\Users\18339\Desktop\ideaprojects\juc>
2、使用 jstack 进程号
找到死锁问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Found one Java-level deadlock: "T2": waiting to lock monitor 0x000002e34e2a0a68 (object 0x00000000d6105220, a java.lang.String), which is held by "T1" "T1": waiting to lock monitor 0x000002e34e2a3248 (object 0x00000000d6105258, a java.lang.String), which is held by "T2" Java stack information for the threads listed above: "T2": at com.lock.MyThread.run(DeadLockDemo.java:38) - waiting to lock <0x00000000d6105220> (a java.lang.String) - locked <0x00000000d6105258> (a java.lang.String) at java.lang.Thread.run(Thread.java:748) "T1": at com.lock.MyThread.run(DeadLockDemo.java:38) - waiting to lock <0x00000000d6105258> (a java.lang.String) - locked <0x00000000d6105220> (a java.lang.String) at java.lang.Thread.run(Thread.java:748) Found 1 deadlock. C:\Users\18339\Desktop\ideaprojects\juc>
面试,工作!排查问题
1、日志
2、堆栈
因为内容太多了,所以将其拆分为以下内容