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(); } }
运行结果