Java锁相关随笔
volatile是什么
-
首先 volatile 是用于轻量级同步机制的
-
他能
- 保证可见性
- 不保证原子性
- 禁止指令重排
-
单例模式里面双重锁机制是典型案例
可见性就是各自线程的工作线程能互相看到别人的
验证代码
public class VolatileTest {
public static void main(String[] args) {
Data data = new Data();
// 线程1
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t start");
//暂停一会
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//更改数据
data.add();
System.out.println(Thread.currentThread().getName() + "\t update 60");
}).start();
//主线程
while (data.a == 0){
//傻傻的转着
}
System.out.println(Thread.currentThread().getName() + "\t over");
}
}
class Data{
int a = 0;
public void add(){
a = 60;
}
}
验证非原子性
public class VolatileTest2 {
public static void main(String[] args) {
Data2 data2 = new Data2();
//20个线程
for (int i = 1; i <= 20; i++) {
new Thread(() -> {
//每个线程累加1000次
for (int j = 0; j < 1000; j++) {
data2.add();
}
}, String.valueOf(i)).start();
}
//主线程等待所有线程执行完毕
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(data2.a); //14246/20000
}
}
class Data2 {
volatile int a = 0;
void add() {
a++;
}
}
CAS的ABA问题
AtomicStampedReference 通过版本号解决 stamp
ArrayList的线程不安全
证明
public class ArrayListTest {
public static void main(String[] args) {
// List<String> list = new ArrayList<>(); //java.util.ConcurrentModificationException
// List<String> list = new Vector<>(); //第一种
// List<String> list = Collections.synchronizedList(new ArrayList<String>()); //第二种
List<String> list = new CopyOnWriteArrayList<>(); //第三种
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
HashSet, Map同理
公平锁/非公平锁/可重入锁/递归锁/自旋锁
可重入锁: 指的是同一个线程外层函数拿到锁, 进里面照样能拿这个锁
自旋锁: 采用循环方式尝试获取锁
自旋代码demo
public class CASTest {
private AtomicReference atomicReference = new AtomicReference();
public void myLock() {
Thread thread = Thread.currentThread();
//
while (!atomicReference.compareAndSet(null, thread)) {
System.out.println(Thread.currentThread().getName() + "等待锁");
}
}
public void myUnlock() {
Thread thread = Thread.currentThread();
atomicReference.compareAndSet(thread, null);
System.out.println(Thread.currentThread().getName() + "释放锁");
}
public static void main(String[] args) {
CASTest casTest = new CASTest();
new Thread(() -> {
casTest.myLock();
//先占用5s
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//释放锁
casTest.myUnlock();
}, "t1").start();
new Thread(() -> {
//先等1s让t1先启动
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
casTest.myLock();
casTest.myUnlock();
}, "t2").start();
}
}
独占锁: 一个锁只能被一个线程占有
共享锁: ReentrantReadWriteLock
代码示例
public class ReadWriteLockTest {
private volatile Map<String, Object> map = new HashMap<>();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void put(String key, Object value) {
lock.writeLock().lock(); //拿写锁
try {
System.out.println(Thread.currentThread().getName() + "开始写入");
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "结束写入");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
public Object get(String key) {
lock.readLock().lock(); //拿读锁
try {
System.out.println(Thread.currentThread().getName() + "开始读取");
Object o = map.get(key);
System.out.println(Thread.currentThread().getName() + "结束读取: " + o);
return o;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
return null;
}
public static void main(String[] args) {
ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
readWriteLockTest.put(Thread.currentThread().getName(), Thread.currentThread().getName());
readWriteLockTest.get(Thread.currentThread().getName());
}, "t" + i).start();
}
}
}
t4开始写入
t4结束写入
t3开始写入
t3结束写入
t1开始写入
t1结束写入
t2开始写入
t2结束写入
t5开始写入
t5结束写入
t5开始读取
t4开始读取
t4结束读取: t4
t3开始读取
t3结束读取: t3
t5结束读取: t5
t1开始读取
t1结束读取: t1
t2开始读取
t2结束读取: t2
CountDownLatch
让线程阻塞等待另外一些线程完毕
代码示例
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "号同学离开教室");
countDownLatch.countDown();
}, "同学" + i).start();
}
countDownLatch.await();
System.out.println("※※※※※※※班长锁门");
}
}
CyclicBarrier
人到齐了才能开饭
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(4, () ->
System.out.println("人到齐了..开饭...")
);
for (int i = 1; i <= 4; i++) {
final int tmpI = i;
new Thread(() -> {
System.out.println("第" + tmpI + "个人到了...");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
}, "t" + i).start();
}
}
}
第2个人到了...
第1个人到了...
第4个人到了...
第3个人到了...
人到齐了..开饭...
Semaphone
抢车位
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); //3个车位
//六辆车
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + "\t抢到车位🅿");
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + "\t离开车位🚗");
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
semaphore.release();
}
}, "car" + i).start();
}
}
}
car2 抢到车位🅿
car1 抢到车位🅿
car3 抢到车位🅿
car1 离开车位🚗
car2 离开车位🚗
car3 离开车位🚗
car5 抢到车位🅿
car6 抢到车位🅿
car4 抢到车位🅿
car4 离开车位🚗
car6 离开车位🚗
car5 离开车位🚗