玩命加载中🤣🤣🤣

Java锁相关随笔


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	离开车位🚗

文章作者: 👑Dee👑
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 👑Dee👑 !
  目录