看完后,你再也不用怕面试问并发编程啦( 十 )


ReentrantLock
Lock使用标准方式l.lock(); // 获得锁try {操作共享资源的代码} finally {l.unlock(); // 释放锁} 代码:package cn.itcast.thread;import java.util.concurrent.locks.ReentrantLock;/** 学习使用Lock解决线程安全问题 */public class Test10 {// 定义票的总数量private static int ticket = 100;public static void main(String[] args) {// 创建可重入锁对象ReentrantLock lock = new ReentrantLock();Runnable runnable = () -> {// 循环卖票while (true) {try {Thread.sleep(10);// 获得锁lock.lock();if (ticket > 0) {ticket--;System.out.println(Thread.currentThread().getName() +"卖了一张票,剩余:" + ticket);} else {break;}} catch (InterruptedException e) {e.printStackTrace();} finally {// 释放锁lock.unlock();}}};// 创建3个线程Thread t1 = new Thread(runnable, "窗口1");Thread t2 = new Thread(runnable, "窗口2");Thread t3 = new Thread(runnable, "窗口3");t1.start();t2.start();t3.start();}} 13、Java中的锁:ReentrantReadWriteLock目标:掌握Readwriterlock读写锁分析和场景
ReadWriteLock接口介绍
ReadWriteLock也是一个接口,在它里面只定义了两个方法:package java.util.concurrent.locks;public interface ReadWriteLock { Lock readLock(); Lock writeLock();} 一个用来获取读锁,一个用来获取写锁 。也就是说将文件的读写操作分开,分成2个锁来分配给线程 , 从而使得多个线程可以同时进行读操作 。下面的ReentrantReadWriteLock实现了ReadWriteLock接口 。
ReentrantReadWriteLock介绍
ReentrantReadWriteLock里面提供了很多丰富的方法,不过最主要的有两个方法:readLock() 和 writeLock()用来获取读锁和写锁 。
ReentrantReadWriteLock可重入读写锁package cn.itcast.thread;import java.util.concurrent.locks.ReentrantReadWriteLock;// ReentrantReadWriteLock: 可重入读写锁 (读锁是共享锁 , 写锁是独享锁)public class Test11 { // 定义可重入读写锁 private ReentrantReadWriteLock rw = new ReentrantReadWriteLock(); public static void main(String[] args) { final Test11 test = new Test11();new Thread(() -> { test.get(Thread.currentThread()); }).start(); new Thread(() -> { test.get(Thread.currentThread()); }).start(); } public void get(Thread thread) { // 读锁是共享锁 rw.readLock().lock(); // 写锁是独享锁 //rw.writeLock().lock(); try { for (int i = 0; i < 50; i++){ System.out.println(thread.getName() + "正在进行读操作"); } System.out.println(thread.getName() + "读操作完毕"); }finally { rw.readLock().unlock(); //rw.writeLock().unlock(); } }} 小结
ReentrantReadWriteLock的优势与应用场景
1. 大大提升了读操作的效率 。
2. 不过要注意的是 , 如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁 。
3. 如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁 , 则申请的线程会一直等待释放写锁 。
4. ReentrantReadWriteLock适合读多写少的应用场景14、原子更新基本类型目标:掌握java.util.concurrent.atomic包下原子更新基本类型
介绍
Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式 。actomic实现原子性操作采用的是CAS算法保证原子性操作,性能高效 。
CAS原理分析:
使用CAS(Compare-And-Swap)比较并交换,操作保证数据原子性
CAS算法是 JDK对并发操作共享数据的支持 , 包含了3个操作数
第一个操作数:内存值value(V)
第二个操作数:预估值expect(E)
第三个操作数:更新值new(N)
含义:当多线程每个线程执行写的操作时 , 每个线程都会读取主存最新内存值value,并设置预估的值 , 只有最新内存值与预估值一致的线程,就会将需要更新的值更新到主存中 , 其他线程就会失败保证原子性操作;这样就解决了synchronized排队导致性能低下的问题 。

看完后,你再也不用怕面试问并发编程啦

文章插图
java.util.concurrent.atomic包的原子类:
看完后,你再也不用怕面试问并发编程啦

文章插图
原子更新基本类型 类含义AtomicBoolean原子更新布尔类型AtomicInteger原子更新整型AtomicLong原子更新长整型 上面3个类提供方法完全一样,所以我们以AtomicInteger为例进行讲解API方法:


推荐阅读