java同步手段

前言

看来很多java同步的各种策略,现在我们来总结一下一共有哪些呢

正文

1、synchronized和ReentrantLock

每个对象都会持有一个monitor,最开始一个对象的monitor会指向null,用 synchronized修饰代码块的时候,会默认在代码块的前面和后面分别加上enter和exit指令,当执行到enter指令时就会检测 monitor 是否为空,如果是的话就会把当前线程赋给monitor,如果不是就阻塞;当执行到exit的时候就会把monitor设置为空

ReentrantLock与synchronized不同,它是封装好的工具类,不像synchronized是基于JVM的,所以需要使用lock和unlock来手动获取与释放锁,而正是因为此则更加灵活,此外,相较于synchronized,它还有其他优点

  • 可以实现公平锁,先来先到
  • 可重入,当该线程再次试图获取锁时,自动成功
  • 带超时的获取锁尝试
  • 条件变量代替了Object的 wait/notify,变得很直观

但并不是说synchronized一定就比ReentrantLock差,在jdk1.5之前,synchronized是个重量级锁,因为monitor指令是调用操作系统的排他锁来实现的,它要从用户态转到核心态,所以不太好,在1.6之后做了优化,例如说偏向锁、自旋锁的产生优化了synchronized的处理,所以说现在synchronized不一定比ReentrantLock性能差。

2、CyclicBarrier 与CountDownLatch

CountDownLatch 的功能类似一个计时器,等到我们规定的时间后就会执行,例如这个场景:假设你的系统要启动,启动之前需要做很多配置准备工作,这些任务你分别交给了几个线程去执行,当这些操作都完成之后你才能启动系统,那么怎么解决这个线程同步的问题呢?这里用CountDownLatch就很好解决,让每个子线程执行完成之后,countdown(),主线程调用await()阻塞方法,当getcount为0 的时候await就会往下执行,这样就完成了

而CyclicBarrier 的功能类似与一辆卡车,假设车上有5个位置,要等到陆陆续续人来了,把座位坐满了才会出发,
送完人之后就可以继续接着来一批。假设设定的5的话,那么必须在5个子线程中调用await(),之后每个线程都会往后执行,不然都会阻塞在那里,直到执行了5次await(),

public class CyclicBarrierDemo {
    
    public static void main(String[] args) {
       new CyclicBarrierDemo().action();

    }
    public void action(){
        CyclicBarrier barrier = new CyclicBarrier(3);
        Thread thread = new Thread(new CyclicThread(barrier,"A"));
        thread.start();
        System.out.println("---------wait---------");
        Thread thread1 = new Thread(new CyclicThread(barrier,"B"));
        thread1.start();
    }

    class CyclicThread implements Runnable{

        private CyclicBarrier barrier;
        private String name;
        public CyclicThread(CyclicBarrier barrier,String name){
            this.barrier = barrier;
            this.name = name;
        }
        @Override
        public void run() {
            try {
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(name + "-> begin");
        }
    }
}

那么我们来总结一下两者的区别的

  • CountDownLatch 无法被重用,而CyclicBarrier 可以循环使用
  • CountDownLatch 的基本操作组合是 countDown/await。调用 await 的线程阻塞等待countDown 足够的次数;CyclicBarrier 是等待所有的线程都调用了await ,才会往后执行。

你可能感兴趣的:(java同步手段)