CountDownLanuch,CyclicBarrier,Semaphore,Lock

A. You used CountDownLanuch, CyclicBarrier, Semaphore do in the project?

  1.CountDownLanuch synchronization is a utility class that allows one or more threads wait until the other thread completes execution will continue in the future.

     By initializing a counter internal counter of the number of threads is achieved, whenever a thread is finished, it is decremented by 1 when the counter reaches zero, indicating that all

     Threads are finished, you can continue behind the code (similar to a rocket launch countdown)

public  static  void show01 ( int n-) { 
      
        a CountDownLatch CountDownLatch = new new a CountDownLatch (n-); // number counter is initialized thread 

        // opening 6 threads, when CountDownLatch reduced to 0, the main thread runs 
        for ( int I =. 1; I <=. 6; I ++ ) {
             new new the Thread (() -> { 
                System.out.println (. Thread.currentThread () getName () + "\ T night classes, leave the room" ); 
                countDownLatch.countDown (); / / counter is decremented. 1 
            }, String.valueOf (I)) Start ();. 
        } 

        the try {
            CountDownLatch.await ();// counter waits 
        } the catch (InterruptedException E) { 
            e.printStackTrace (); 
        } 
        System.out.println (. Thread.currentThread () getName () + "\ T monitor finally closed, leaving" ); 
    }

operation result

 

 

   The second case: using a combination of enumeration

public static void show02(int n){
        CountDownLatch countDownLatch = new CountDownLatch(n);
        for (int i = 1; i <= n; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"被灭了");
                countDownLatch.countDown();
            },CountryEnum.list(i).getRetCode()).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
        System.out.println (Thread.currentThread () getName (). + "\ T united Qin" ); 

    }
public enum CountryEnum {
    ONE(1,"齐国"),TWO(2,"楚国"),THREE(3,"燕国"),
    FOUR(4,"赵国"),FIVE(5,"魏国"),SIX(6,"韩国");

    private Integer retId;
    private String retCode;

    public Integer getRetId() {
        return retId;
    }

    public String getRetCode() {
        return retCode;
    }

    CountryEnum(Integer retId, String retCode) {
        this.retId = retId;
        this.retCode = retCode;
    }

    CountryEnum() {
    }

    public static CountryEnum List ( int index) {
         // by thread number, obtaining the corresponding country 
        CountryEnum [] = Countries CountryEnum.values ();
         for (CountryEnum Country: Countries) {
             IF (country.getRetId () == index) {
                 return Country; 
            } 
        } 
        return  null ; 
    } 
}

operation result

 

 

   2.CyclicBarrier it refers to the use of recyclable barrier, its main function is blocked so that when a group of threads reach a barrier, until the last thread reaches the barrier

    , The barrier will open the door, all intercepted thread will continue to work, barriers to entry is the thread that calls await method (analogous to a meeting, people in attendance will be able to start)

public  static  void main (String [] args) {
         // when seven thread of execution has been completed, the thread will execute CyclicBarrier counter is incremented. 1 
        CyclicBarrier CyclicBarrier = new new CyclicBarrier (. 7, () -> { 
            System.out.println ( "people in attendance, meeting start" ); 
        }); 
        for ( int I =. 1; I <=. 7; I ++ ) {
             Final  int temInt = I;
             new new the Thread (() -> {
                 the try { 
                    the System.out. println ( "first" + temInt + "individual has entered the conference room to wait" ); 
                    CyclicBarrier.await (); 
                } the catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }


    }

operation result

 

 

   3.Semaphore semaphore for mutual exclusion using more shared resources for controlling concurrent threads (analogous to, grab parking spaces)

public static void main(String[] args) {
        //有3个停车位,6辆车
        Semaphore semaphore = new Semaphore(3);//3个车位
        for (int i = 1; i <= 6; i++) {
            final int tmpInt = i;
            new Thread(() ->{
                try {
                    semaphore.acquire();//获取资源
                    System.out.println("第"+tmpInt+"号车抢到车位");
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println("第"+tmpInt+"号车,停了5秒...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();//释放资源,再来获取资源,直到所有的线程都执行完毕
                }
            },String.valueOf(i)).start();
        }
    }

运行结果

 

 

 

二. 请你谈谈对锁的理解,什么是公平锁/非公平锁,什么是递归锁,什么是读写锁,什么是自旋锁,是否可以写一个自旋锁

  1.公平锁/非公平锁

    公平锁:在并发环境下,每个线程在获取锁的时候会先查看锁等待的序列,如果为空,或者当前线程是等待队列的第

      一个,就占着锁,以后会按照先进先出的顺序从队列中依次的执行(类比于,排队问问题)

    非公平锁:线程上来就直接尝试占有锁,如果尝试失败,就采用公平锁的策略(类比于,排队问问题,有人插队,但被喝止,只能排队)

    非公平锁的优点在于吞吐量比公平锁大   

     1.Lock lock = new ReentrantLock(); fair默认为false 是非公平锁,如果fair为true,就是公平锁

     2.synchronized 而言,它是非公平锁

  2.递归锁(可重用锁)

     递归锁:指的是同一个线程,外层的函数获得锁之后,内层的递归函数任然可以获取该锁的递归代码.在同一个线程在外层

       方法获取锁的时候,在进入内层方法就会自动的获取锁.也就是说,线程可以进入任何一个它已经拥有锁的同步代码块

       (类比于获得了大门的钥匙,在进入厨房,不需要再开锁)

        ReentrantLock和 Synchronized 都是可重用锁

   优点:这样可以避免死锁的产生

   面试题:多个Lock对象会不会产生编译错误/运行错误

    多个Lock对象不会产生编译错误,运行错误,如果lock,unlock可以正常匹配,那么代码会正常执行,退出.如果不匹配,线程就不会释放锁

    从而,会一直请求释放锁对象,即卡死

 

class Phone implements Runnable{
    // 发短信,成功的话调用法Email的方法
    public synchronized void sendSMS() throws Exception{
        System.out.println(Thread.currentThread().getName() + "\t" + "invoke sendSMS");
        sendEmail();
    }

    public synchronized void sendEmail() throws Exception{
        System.out.println(Thread.currentThread().getName() + "\t" + "invoke sendEmail");
    }

    Lock lock = new ReentrantLock();
    @Override
    public void run() {

        get();
    }
    //get方法,里面调用了set方法
    public void get(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t" + "invoke get");
            set();
        }catch (RuntimeException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void set(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t" + "invoke set");
        }catch (RuntimeException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
/*使用synchronized证明可重用锁*/
    public static void show1(Phone phone){
        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"T1").start();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"T2").start();
    }

运行结果:

/*使用ReentrantLock来证明可重用锁*/
    public static void show2(Phone phone) {
        Thread t3 = new Thread(phone,"T3");
        Thread t4 = new Thread(phone,"T4");
        t3.start();
        t4.start();
    }

运行结果

 

   3.读写锁

      读写锁:多线程共同读一份资源类没有问题,为了满足业务的并发量,多线程读取共享的资源可以同时进行,但是

   如果有一个线程需要对资源进行修改,就不应该让其他的线程对该资源进行读写操作

   读  -  读   可以共存

   读  -  写   不可共存

      写  -  写   不可共存

class MyCache{
    // 存放数据,操作数据
    private volatile Map<String,Object> map = new HashMap<>();
    // 读写锁
    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    // 写操作
    public void put(String key,Object value){
        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t写入数据");
            TimeUnit.MICROSECONDS.sleep(500);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName() + "\t写入完成");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            rwLock.writeLock().unlock();
        }
    }
 
    // 读操作
    public void get(String key){
        rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t读取数据");
            TimeUnit.MICROSECONDS.sleep(500);
            Object value = map.get(key);
            System.out.println(Thread.currentThread().getName() + "\t读取完成"+value);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            rwLock.readLock().unlock();
        }
    }

    public void clear(){
        map.clear();
    }
}
 public static void main(String[] args) {
        MyCache ca = new MyCache();
        // 启用5个线程,同时进行写操作
        for (int i = 1; i <= 5; i++) {
            final int temInt = i;
            new Thread(()->{
                ca.put(temInt+"",temInt+"");
            },String.valueOf(i)).start();
        }

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 启用5个线程,同时进行读操作
        for (int i = 1; i <= 5; i++) {
            final int temInt = i;
            new Thread(()->{
                ca.get(temInt+"");
            },String.valueOf(i)).start();
        }
    }

运行结果

 

 

  多线程下的读/写操作没有插队

  4.自旋锁

     自旋锁:尝试获取锁的线程不会立刻阻塞,而是采取循环的方式去获取锁,这样可以减少线程上下文切换的消耗,但会

   增大CPU的开销

public class SingleLock {

    /*手写一个自旋锁*/
    static AtomicReference<Thread> atomicReference = new AtomicReference<>();

    /*加锁*/
    public static void lock(){
        /*如果当前没有线程,则使用当前线程*/
        System.out.println(Thread.currentThread().getName() + "\tget lock");
        // 如果当前的线程不是第一次进来,就会在while这里一直死循环,程序无法进行
        while (!atomicReference.compareAndSet(null,Thread.currentThread())){

        }
    }

    /*解锁*/
    public static void unLock(){
        /*如果判断是当前的线程,则清空*/
        System.out.println(Thread.currentThread().getName() + "\tinvoke lock");
        atomicReference.compareAndSet(Thread.currentThread(),null);
    }

    /*自旋锁*/
    public static void main(String[] args) {
        
        new Thread(() ->{
            lock();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            unLock();
        },"T1").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            lock();
            unLock();
        },"T2").start();
    }
}

运行结果

 

Guess you like

Origin www.cnblogs.com/luhuajun/p/12157601.html