一、原子引用java
package com.example.mybaties; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; import java.util.concurrent.atomic.AtomicReference; /** * @DESCRIPTION 原子引用 * @Author lst * @Date 2020-03-24 09:00 */ public class AtomicReferenceDemo { public static void main(String[] args) { User z3 = new User("z3",22); User li4 = new User("li4",25); AtomicReference<User> atomicReference = new AtomicReference(); atomicReference.set(z3); System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString()); System.out.println(atomicReference.compareAndSet(z3,li4)+ "\t " + atomicReference.get().toString());//主物理内存已经变成li4 /** * true User(userName=li4, age=25) * false User(userName=li4, age=25) */ } } @Getter @ToString @AllArgsConstructor class User { String userName; int age; }
二、可重入锁api
package com.example.mybaties; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @DESCRIPTION 可重入锁(也叫递归锁) * 指的是同一线程外层脳数得到锁以后,内层递归数仍然能获取该锁的代吗,在同一个线程在外层方法英取的时候, * 在进入内层方法会自动获取锁也便是说,线程能够进入一个任何它已经拥有的所同歩的代码块 * * * 就是一个典型的可重入锁 * * 11invoked sendSms * 11#######invoked sendEmail * 12invoked sendSms * 12#######invoked sendEmail * * * * @Author lst * @Date 2020-03-23 14:48 */ class Phone implements Runnable{ public synchronized void sendSms(){ System.out.println(Thread.currentThread().getId() + "invoked sendSms "); sendEmail(); } public synchronized void sendEmail(){ System.out.println(Thread.currentThread().getId() + "#######invoked sendEmail "); } Lock lock = new ReentrantLock();//默认非公平锁 @Override public void run() { get(); } public void get(){ lock.lock(); lock.lock(); System.out.println(Thread.currentThread().getName() + " invoked get() "); set(); lock.unlock(); lock.unlock(); } public void set(){ lock.lock(); System.out.println(Thread.currentThread().getName() + " ####invoked set() "); lock.unlock(); } } public class ReenterLockDemo { public static void main(String[] args) { Phone phone = new Phone(); new Thread(() -> { phone.sendSms(); },"t1").start(); new Thread(() -> { phone.sendSms(); },"t2").start(); //暂停一会 try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(); System.out.println(); System.out.println(); System.out.println(); System.out.println(); Thread t3 = new Thread(phone,"t3"); Thread t4 = new Thread(phone,"t4"); t3.start(); t4.start(); /** * 14invoked sendSms * 14#######invoked sendEmail * 13invoked sendSms * 13#######invoked sendEmail * * * * * * t3 invoked get() * t3 ####invoked set() * t4 invoked get() * t4 ####invoked set() */ } }
三、读写锁多线程
/** * @DESCRIPTION 读写锁 *多个线程同时读一个资源关没有任何问题,因此为了知足并发量,读取共享资源应该能够同时进行 * 可是若是有一个线程想去写共享资源来,就不该该再有其它线程能够对该资源进行读或写 * 小总结 * 读-读能共存 * 读-写不能共存 * 写不能共存 * * * 写操做:原子(完整一致性)+独占,整个过程必须是一个完整的统一体,中间不能间断 * * @Author lst * @Date 2020-03-24 12:00 */ 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()+" 正在写入: " +key); //暂停一会线程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } map.put(key,value); System.out.println(Thread.currentThread().getName()+" 写入完成: " ); }catch (Exception e){ e.getMessage(); }finally { rwLock.writeLock().unlock(); } } public void get(String key){ //读锁 rwLock.readLock().lock(); try { System.out.println(Thread.currentThread().getName()+" 正在读取: " +key); //暂停一会线程 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } Object result = map.get(key); System.out.println(Thread.currentThread().getName()+" 读取完成: " + result); }catch (Exception e){ e.getMessage(); }finally { rwLock.readLock().unlock(); } } public void clearMap(){ map.clear(); } } public class ReentranRreadWriteLockDemo { public static void main(String[] args) { MyCache myCache = new MyCache(); for (int i = 0; i < 5; i++) { final String keyValue = String.valueOf(i); new Thread(() -> { myCache.put(keyValue,keyValue); },keyValue).start(); } for (int i = 0; i < 5; i++) { final String keyValue = String.valueOf(i); new Thread(() -> { myCache.get(keyValue); },keyValue).start(); } /* 0 正在写入: 0 0 写入完成: 1 正在写入: 1 1 写入完成: 2 正在写入: 2 2 写入完成: 3 正在写入: 3 3 写入完成: 4 正在写入: 4 4 写入完成: 0 正在读取: 0 1 正在读取: 1 2 正在读取: 2 3 正在读取: 3 4 正在读取: 4 0 读取完成: 0 1 读取完成: 1 2 读取完成: 2 3 读取完成: 3 4 读取完成: 4 */ ShareResource shareResource = new ShareResource(); new Thread(() -> { for (int i = 1; i <= 10; i++) { shareResource.print5(); } },"A").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { shareResource.print10(); } },"B").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { shareResource.print15(); } },"C").start(); } }
四、synchronized和lock有什么区别?用新的lock有什么好处?你挙例说说并发
/** * 题目: synchronized 和lock有什么区别?用新的lock有什么好处?你挙例说说 * 一、原始构成 * synchronized是关字jvm层面, * monitorenter(底层是经过monitor对象来完成,其实wait/ notify等方法也依 monitor对象只有在同步块或方法中能源ait/ notify等方 * monitorexit * Lock是具体类(java,utiL, concurrent. Locks.Lock)是api层面的锁 * 二、使用方法 * synchronized 不须要用户去手动释放锁,当 synchronized代码执行完后系统会自动让线程释放对锁的占用 * Reentrantlock则须要户去手动释放锁,若没有主动释放锁,就有可能致使出现死锁现象。须要Lock()和unLock()方法配合try/ finally语句块来完成 * 三、等待是否可中断 * synchronized 不可中断,除非抛出异常或者正常运行完成 * Reentrantlock 可中断, * 1.设置超时方法 trylock( long timeout, Timeunit unit) * 2. LockInterruptibly()放代码块中,调 interrupt()方法可中断 * 四、加锁是否公平 * synchronized非公平锁 * Reentrantlock 二者均可以,默认非公平锁,构造方法能够传入 boolean值,true为公平锁, false为非公平锁 * * 五、锁绑定多个条件 Condition * synchronized没有 * Reentrantlock,用来实分组唤要唤的线程,能够精确唤醒,而不是像 synchronized要么随机唤醒一个线程 要么唤醒所有线程 * * * 原始构成:synchronized是JVM层面的,底层经过monitorenter和monitorexit来实现的。Lock是JDK API层面的。(synchronized一个enter会有两个exit,一个是正常退出,一个是异常退出(保证确定能够退出)) * 使用方法:synchronized不须要手动释放锁,而Lock须要手动释放。 * 是否可中断:synchronized不可中断,除非抛出异常或者正常运行完成。Lock是可中断的,1.设置超时方法tryLock(long timeout,TimeUnit unit); 2. lockInterruptibly()方法放代码块中,调用interrupt() * 是否为公平锁:synchronized只能是非公平锁,而ReentrantLock既能是公平锁,又能是非公平锁,构造方法传入false/true,默认是非公平锁false。 * 绑定多个条件:synchronized不能,只能随机唤醒。而Lock能够经过Condition来绑定多个条件,精确唤醒。 * * * 题目:多线程之按顺序调用,实现A->B->C三个线程启动,要求以下 * AA打印5次,BB打印10次,CC打印15次 * 紧接着 * AA打印5次,BB打印10次,CC打印15次 * 。。。。。。 * 来10轮 * */ class ShareResource{ private int number = 1;//A:1 B:2 C:3 private Lock lock = new ReentrantLock(); private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); public void print5(){ lock.lock(); try{ //一、判断 while (number != 1){ c1.await(); } //二、干活 for (int i = 1; i <= 5 ; i++) { System.out.println(Thread.currentThread().getName()+" " + i); } //三、通知 number = 2; c2.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void print10(){ lock.lock(); try{ //一、判断 while (number != 2){ c2.await(); } //二、干活 for (int i = 1; i <= 10 ; i++) { System.out.println(Thread.currentThread().getName()+" " + i); } //三、通知 number = 3; c3.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } } public void print15(){ lock.lock(); try{ //一、判断 while (number != 3){ c3.await(); } //二、干活 for (int i = 1; i <= 15 ; i++) { System.out.println(Thread.currentThread().getName()+" " + i); } //三、通知 number = 1; c3.signal(); }catch (Exception e){ e.printStackTrace(); }finally { lock.unlock(); } }