手写一个自旋锁(底层是CAS)
主要就是获得锁lock()的地方应用了CAS
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/*
* 手写一个自旋锁(底层是CAS)
*/
public class SpinlockDemo {
// 原子引用,解决JMM中原子性问题,底层是unsafe类,其下面的各个方法是CAS在java中的体现
AtomicReference<Thread> reference = new AtomicReference<Thread>();
public void lock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "\t 来了! ");
do {
// 循环
} while (!reference.compareAndSet(null, thread));
}
private void unlock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "\t 释放了锁! ");
reference.compareAndSet(thread, null);
}
public static void main(String[] args) {
SpinlockDemo spinlockDemo = new SpinlockDemo();
new Thread(() -> {
spinlockDemo.lock();
// System.out.println(Thread.currentThread().getName() + "\t 来了! ");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
spinlockDemo.unlock();
// System.out.println(Thread.currentThread().getName() + "\t 释放了锁!
// ");
}, "first").start();
new Thread(() -> {
spinlockDemo.lock();//如果first不释放锁,这个second就一直在这里自旋
System.out.println(Thread.currentThread().getName() + "\t 终于轮到我了! ");
spinlockDemo.unlock();
// System.out.println(Thread.currentThread().getName() + "\t 释放了锁!
// ");
}, "second").start();
}
}
输出:
first 来了!
second 来了!
first 释放了锁!
second 终于轮到我了!
second 释放了锁!
单例模式,DCL版+volatile禁止重排
/*
* 单例模式,DCL版+volatile禁止重排
*/
public class Singleton {
// 这个地方是懒汉式,如果下面没有if判断,就是饿汉式,防止面试问到
// 这里加volatile是为了防止指令重排
private static volatile Singleton instance = null;
// 精髓之处,将constructor私有化
private Singleton() {
System.out.println("dddd");
}
public static Singleton getInstance() {
if (instance == null) {
// 这里的synchronized是DCL双重锁检测,
// 就像去房间,先敲门,进去了再按按门,看有没有锁严实,再做事
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
//test
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->Singleton.getInstance(),String.valueOf(i)).start();;
}
}
}
测试volatile保证可见性
import java.util.concurrent.TimeUnit;
/*
* 测试volatile保证可见性
*/
public class Seeable {
// 外部类可以通过实例访问内部类的私有变量
static class MyData {
private int num = 0;
// private volatile int num = 0; 此处加上volatile保证可见性
public void changeData() {
this.num = 10;
}
}
public static void main(String[] args) {
MyData myData = new MyData();
// 乃木达表达式,期间用TimeUnit让线程休眠3秒
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " come in");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 改变数据
myData.changeData();
System.out.println("num = " + myData.num);
}, "Ding").start();
// 如果num没有用colatile修,那么mian和Ding线程之间是不可见的,对于main来说,num一直为0,就会一直在这里循环,出不去
while (myData.num == 0) {
}
// 如果num加了volatile修饰,就会执行到这里,并打印这句话
System.out.println(Thread.currentThread().getName() + " mission complete");
}
}
测试volatile不保证原子性
import java.util.concurrent.atomic.AtomicInteger;
/*
* 测试volatile不保证原子性
*/
class MyData {
volatile int num = 1;
public void addNum() {
num++;
}
// 因为colatile不保证原子性,这里用JUC里面的AtomicInteger类,构造函数里面的值是初始化value,默认为0
AtomicInteger atomicInteger = new AtomicInteger(1);
public void atomicAddNum() {
atomicInteger.getAndAdd(1); // 相当于i++,参数是每次加多少
}
}
public class AtonicTest {
public static void main(String[] args) {
MyData myData = new MyData();
for (int i = 0; i < 20; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
// myData.addNum();
// 这里用AtomicInteger类的方法,保证原子性
myData.atomicAddNum();
}
}, String.valueOf(i)).start();
}
// 如果后台线程大于2(后台默认有一个main和GC线程),就让线程继续执行
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println("最终的num值是: " + myData.atomicInteger);
}
}
测试syn可重入锁
/*
* 测试syn可重入锁
*/
public class SynDemo {
static class Phone {
public synchronized void getName() {
System.out.println(Thread.currentThread().