主页 > 游戏开发  > 

三、Java中七大常用锁实战

三、Java中七大常用锁实战
1、锁的7大分类

2.Lock接口的常见方法有哪些?

解释:

        1.lock() - 加锁

        2.lockInterruptibly() - 实现可中断的锁

        3.tryLock() - 尝试获取锁,只会尝试一次

        4.unlock() - 解锁

        5.newCondition() - 

方法示例:

void lock() -  package imooc4.lock; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: 测试lock接口 */ public class TestLock { static int count = 0; public static void main(String[] args) throws InterruptedException { Lock lock = new ReentrantLock(); //模拟多个线程执行++操作 结果1000 List<Thread> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { Thread thread = new Thread(() -> { for (int j = 0; j < 100; j++) { lock.lock(); try { count++; } finally { lock.unlock(); } } }); list.add(thread); } for (Thread thread : list) { thread.start(); } for (Thread thread : list) { thread.join(); } System.out.println(count);//如果是1000结果就是正确的 } } 运行结果: boolean tryLock() -  package imooc4.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: * Lock lock = ...; * * if (lock.tryLock()) { * * try { * * // manipulate protected state * * } finally { * * lock.unlock(); * * } * * } else { * * // perform alternative actions * * }}</pre> */ public class TestTryLock { public static void main(String[] args) { Lock lock = new ReentrantLock(); for (int i = 0; i < 10; i++) { new Thread(()->{ if(lock.tryLock()){ try { System.out.println("拿到了锁"); Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } }else{ System.out.println("没拿到锁"); } }).start(); } } } 运行结果: boolean tryLock(long time, TimeUnit unit) - package imooc4.lock; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: */ public class TestTryLockWithTimeOut { public static void main(String[] args) { Lock lock = new ReentrantLock(); Thread thread = new Thread(() -> { try { if (lock.tryLock(1, TimeUnit.SECONDS)) { System.out.println(Thread.currentThread().getName() + " 拿到了锁"); } else { System.out.println(Thread.currentThread().getName() + " 没拿到锁"); return; } } catch (InterruptedException e) { throw new RuntimeException(e); } try { //临界资源的操作 System.out.println(Thread.currentThread().getName() + " 正在操作临界资源"); Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } }); Thread thread1 = new Thread(() -> { try { if (lock.tryLock(1, TimeUnit.SECONDS)) { System.out.println(Thread.currentThread().getName() + " 拿到了锁"); } else { System.out.println(Thread.currentThread().getName() + " 没拿到锁"); return; } } catch (InterruptedException e) { throw new RuntimeException(e); } try { //临界资源的操作 System.out.println(Thread.currentThread().getName() + " 正在操作临界资源"); Thread.sleep(2000); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } }); thread.start(); thread1.start(); } }

运行结果:

3.Lock锁如何实现生产者消费者模式-Condition接口? 

之前实现的场景

之前是通过锁对象的wait()和notifyAll()实现的吃自助餐的场景

现在通过Lock和Condition实现

、如果只有一个Condtion,那它的和Synchronized的实现机制是一样的,如果创建多个Condtion,会让等待唤醒机制更加灵活。

 

package imooc4.condition; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: */ public class Desk { //标注桌子上是否有食物 public static boolean flag = false; public static final Lock lock = new ReentrantLock(); //给consumer用的condition public static Condition condition4Consumer = lock.newCondition(); //给producer用的condition public static Condition condition4Producer = lock.newCondition(); } package imooc4.condition; /** * @Description: */ public class Consumer extends Thread{ @Override public void run() { while (true){ //不断地拿食物 Desk.lock.lock(); try { if(Desk.flag){ //如果有实物 拿走,并通知厨师 System.out.println("顾客取走食物"); Desk.flag = false; System.out.println("consumer 准备唤醒producer"); Desk.condition4Producer.signalAll(); }else{ try { Desk.condition4Consumer.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }finally { Desk.lock.unlock(); } } } } package imooc4.condition; /** * @Description: */ public class Producer extends Thread{ @Override public void run() { while (true){ Desk.lock.lock(); try { if(Desk.flag){ //厨师等待 try { Desk.condition4Producer.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } }else{ //厨师开始工作 System.out.println("厨师正在补充食物"); Desk.flag = true; System.out.println("producer 准备唤醒consumer"); Desk.condition4Consumer.signalAll(); } }finally { Desk.lock.unlock(); } } } } package imooc4.condition; /** * @Description: */ public class TestConsumerAndProducer { public static void main(String[] args) { Producer producer = new Producer(); Producer producer1 = new Producer(); Producer producer2 = new Producer(); Producer producer3= new Producer(); Consumer consumer = new Consumer(); Consumer consumer1 = new Consumer(); Consumer consumer2 = new Consumer(); Consumer consumer3 = new Consumer(); producer.start(); producer1.start(); producer2.start(); producer3.start(); consumer.start(); consumer1.start(); consumer2.start(); consumer3.start(); } }

运行结果:

4.选用锁时该用synchronized关键是还是Lock接口?

5.公平锁与非公平锁应该选用哪个?

公平锁 - 

package imooc4.fair; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: 测试公平锁 */ public class TestFairLock { //公平锁 static Lock lock = new ReentrantLock(true); public static void main(String[] args) { //创建多个线程,每个线程多次加锁, // 拿到锁后检查时哪个线程拿到的锁 for (int i = 0; i < 3; i++) { new Thread(()->{ for (int j = 0; j < 2; j++) { //加锁 lock.lock(); try { System.out.println("当前获取锁的线程"+ Thread.currentThread().getName()); }finally { lock.unlock(); } } }).start(); } } }

运行结果:

非公平锁 - 

package imooc4.fair; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: */ public class TestUnfairLock { //非公平锁 static Lock lock = new ReentrantLock(false); public static void main(String[] args) { //创建多个线程,每个线程多次加锁, // 拿到锁后检查时哪个线程拿到的锁 for (int i = 0; i < 3; i++) { new Thread(()->{ for (int j = 0; j < 2; j++) { //加锁 lock.lock(); try { System.out.println("当前获取锁的线程"+ Thread.currentThread().getName()); }finally { lock.unlock(); } } }).start(); } //A B C //A-1 A-2 //B-1 B-2 //C-1 C-2 } }

运行结果:

6.(可中断和不可中断)如何使用Lock接口实现可中断锁?

代码示例:

package imooc4.interrupt; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * @Description: 测试可中断锁 */ public class TestInterruptLock { static final Lock lock = new ReentrantLock(); public static void main(String[] args) throws InterruptedException { //受害人转账线程 尝试获取可中断锁 Thread thread = new Thread(() -> { try { lock.lockInterruptibly(); } catch (InterruptedException e) { System.out.println("受害人转账操作取消,钱财找回,谢谢民警"); return; } try { System.out.println("受害 人开始转账给骗子"); } finally { lock.unlock(); } }); Thread thread1 = new Thread(() -> { try { lock.lockInterruptibly(); } catch (InterruptedException e) { } try { Thread.sleep(3000); System.out.println("其他的转账线程"); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.unlock(); } }); //其他转账线程执行 thread1.start(); Thread.sleep(100); //受害人转账线程执行 thread.start(); Thread.sleep(100); thread.interrupt(); } }

运行结果:

7.(共享锁独占锁)如何根据读操作和写操作拆分锁粒度-读写锁ReadWriteLock?

所以readLock、writeLock返回的是Lock的实现类。

package imooc4.lock; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @Description:测试读读不互斥,读写互斥 */ public class TestReentrantReadWriteLock { final static ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); final static Lock writeLock = readWriteLock.writeLock(); final static Lock readLock = readWriteLock.readLock(); // final static Lock lock = new ReentrantLock(); public static void main(String[] args) { Thread thread = new Thread(() -> { writeLock.lock(); try { Thread.sleep(1000); System.out.println(System.currentTimeMillis()); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { writeLock.unlock(); } }); Thread thread1 = new Thread(() -> { writeLock.lock(); try { Thread.sleep(1000); System.out.println("要进行写操作,需要与其他读操作互斥,也需要与其他写操作互斥"); System.out.println(System.currentTimeMillis()); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { writeLock.unlock(); } }); thread.start(); thread1.start(); } }

模拟电商场景:

package imooc4.lock.demo; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @Description: */ public class Product { //商品名称 private String name; //价格 private double price; //赠送 private double coupon; private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public String getName() { return name; } public double getPrice() { lock.readLock().lock(); try { return price; }finally { lock.readLock().unlock(); } } public double getCoupon() { lock.readLock().lock(); try { return coupon; }finally { lock.readLock().unlock(); } } public void updateProductInfo(double newPrice,double newCoupon){ lock.writeLock().lock(); try { this.price = newPrice; Thread.sleep(1000); this.coupon = newCoupon; } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.writeLock().unlock(); } } public Product(String name, double price, double coupon) { this.name = name; this.price = price; this.coupon = coupon; } @Override public String toString() { return "Product{" + "name='" + name + '\'' + ", price=" + price + ", Coupon=" + coupon + ", lock=" + lock + '}'; } } package imooc4.lock.demo; /** * @Description: */ public class TestProduct { public static void main(String[] args) throws InterruptedException { Product product = new Product("拉杆箱",200,150); System.out.println(product); Thread writeThread = new Thread(()->{ product.updateProductInfo(150,100); }); Thread readThread = new Thread(() -> { double price = product.getPrice(); double coupon = product.getCoupon(); System.out.println(price); System.out.println(coupon); }); writeThread.start(); Thread.sleep(500); readThread.start(); // System.out.println(product); } }

运行结果:

8.(读写锁)读写锁ReadWriteLock何时使用锁的降级?

大白话:

        释放写锁,再获取读锁,与不释放写锁,先获取读锁,再释放写锁的区别?

释放写锁,再获取读锁 - 就是普通锁的获取与释放的过程,中间会产生时间间隔,锁可能被其他的写线程抢占;

不释放写锁,先获取读锁,再释放写锁 - 这把锁就不会被别的写线程抢占,锁的降级。

注意:

        如果先读锁,再获取写锁 - 这里不是升级锁,而是先读锁解锁,再获取写锁。

代码案例:

package imooc4.lock.demo; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @Description: */ public class Product { //商品名称 private String name; //价格 private double price; //赠送 private double coupon; private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public String getName() { return name; } public double getPrice() { lock.readLock().lock(); try { return price; }finally { lock.readLock().unlock(); } } public double getCoupon() { lock.readLock().lock(); try { return coupon; }finally { lock.readLock().unlock(); } } public void updateProductInfo(double newPrice,double newCoupon){ lock.writeLock().lock(); try { this.price = newPrice; Thread.sleep(1000); this.coupon = newCoupon; } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.writeLock().unlock(); } } public Product(String name, double price, double coupon) { this.name = name; this.price = price; this.coupon = coupon; } @Override public String toString() { return "Product{" + "name='" + name + '\'' + ", price=" + price + ", Coupon=" + coupon + ", lock=" + lock + '}'; } } package imooc4.lock.demo; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Supplier; /** * @Author: Alfred * @ModuleOwner: Alfred * @Description: * * * * class CachedData { * Object data; * boolean cacheValid; * final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); * * void processCachedData() { * rwl.readLock().lock(); * if (!cacheValid) { * // Must release read lock before acquiring write lock * rwl.readLock().unlock(); * rwl.writeLock().lock(); * try { * // Recheck state because another thread might have * // acquired write lock and changed state before we did. * if (!cacheValid) { * data = ...; * cacheValid = true; * } * // Downgrade by acquiring read lock before releasing write lock * rwl.readLock().lock(); * } finally { * rwl.writeLock().unlock(); // Unlock write, still hold read * } * } * * try { * use(data); * } finally { * rwl.readLock().unlock(); * } * } * }} */ public class CachedData<T> { T data; boolean cacheValid; final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void setCacheValid(boolean cacheValid) { this.cacheValid = cacheValid; } /** * 查询缓存或者设置缓存 * 如果缓存有效,则使用缓存 */ public T processCachedData(Supplier<T> supplier){ readWriteLock.readLock().lock(); //如果缓存有效就读 //如果缓存失效,则写 if(!cacheValid){ //必须先解锁在加锁 readWriteLock.readLock().unlock(); readWriteLock.writeLock().lock(); //更新缓存 try { if(!cacheValid){ data = supplier.get(); cacheValid = true; } //锁降级开始 //没有释放锁,这个锁会和其他写线程阻塞,为了保护 ---System.out.println(data); readWriteLock.readLock().lock(); }finally { readWriteLock.writeLock().unlock(); } } try { //使用缓存 return data; }finally { readWriteLock.readLock().unlock(); } } } package imooc4.lock.demo; import org.junit.Test; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** * @Description: 商品上架,更新,下架业务 */ public class ProductService { //商品信息缓存 productName -> CachedData Map<String,CachedData<Product>> map = new ConcurrentHashMap<>(); Map<String,Product> mockDataBase = new HashMap<>(); @Test public void TestCache(){ CachedData<Product> cachedData = new CachedData<Product>(); String productName = "trunk"; Product product = cachedData.processCachedData(() -> new Product(productName, 200, 150)); map.put(productName,cachedData); product.updateProductInfo(150,100); cachedData.setCacheValid(false); //从db查询数据 Product product1 = cachedData.processCachedData(this::queryDataFromDb); System.out.println(product1); } @Test public void testProduct() throws InterruptedException { new Thread(this::saveProduct).start(); Thread.sleep(50); final String productName = "trunk"; //下单线程1 new Thread(()->{ Product product = queryProduct(productName); if(Objects.nonNull(product)){ System.out.println("用户拿着这个"+product.getName()+"下单了,价格:"+product.getPrice()+ "赠送优惠券"+product.getCoupon()); } }).start(); Thread.sleep(50); //更新商品 new Thread(()->updateProduct(productName)).start(); Thread.sleep(50); //模拟并发写缓存 //多个线程同时下单 //下单线程2 new Thread(()->{ Product product = queryProduct(productName); if(Objects.nonNull(product)){ System.out.println("用户拿着这个"+product.getName()+"下单了,价格:"+product.getPrice()+ "赠送优惠券"+product.getCoupon()); } }).start(); //下单线程3 new Thread(()->{ Product product = queryProduct(productName); if(Objects.nonNull(product)){ System.out.println("用户拿着这个"+product.getName()+"下单了,价格:"+product.getPrice()+ "赠送优惠券"+product.getCoupon()); } }).start(); while (true){ } } /** * 商品上架 (保存商品) * @return */ public int saveProduct(){ String productName = "trunk"; Product product = new Product(productName,200,150); //保存数据到数据库 mockDataBase.put(productName,product); return 1; } /** * 查询商品信息 * @param productName * @return */ public Product queryProduct(String productName){ CachedData<Product> cacheData = getCacheData(productName); return cacheData.processCachedData(()->mockDataBase.get(productName)); } private CachedData<Product> getCacheData(String productName) { // //操作1 // CachedData<Product> cachedData = map.get(productName); // if(cachedData==null){ // map.put(productName,new CachedData<>()); // } //操作2 return map pute(productName, (k, v) -> { if (v == null) { return new CachedData<>(); } else { return v; } }); } /** * 更新商品 * @param productName * @return */ public int updateProduct(String productName){ Product product = queryProduct(productName); if(Objects.isNull(product)){ return 0; } product.updateProductInfo(150,100); mockDataBase.put(productName,product); CachedData<Product> cacheData = getCacheData(productName); cacheData.setCacheValid(false); map.put(productName,cacheData); return 1; } /** * 商品下架 * @return */ public int deleteProduct(String productName){ //查询商品 Product product = queryProduct(productName); if(Objects.isNull(product)){ return 0; } mockDataBase.remove(productName); map.remove(productName); return 1; } private Product queryDataFromDb() { return new Product("trunk",150,100); } }

package imooc4.lock.demo; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @Description: */ public class Product { //商品名称 private String name; //价格 private double price; //赠送 private double coupon; private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public String getName() { return name; } public double getPrice() { lock.readLock().lock(); try { return price; }finally { lock.readLock().unlock(); } } public double getCoupon() { lock.readLock().lock(); try { return coupon; }finally { lock.readLock().unlock(); } } public void updateProductInfo(double newPrice,double newCoupon){ lock.writeLock().lock(); try { this.price = newPrice; Thread.sleep(1000); this.coupon = newCoupon; } catch (InterruptedException e) { throw new RuntimeException(e); } finally { lock.writeLock().unlock(); } } public Product(String name, double price, double coupon) { this.name = name; this.price = price; this.coupon = coupon; } @Override public String toString() { return "Product{" + "name='" + name + '\'' + ", price=" + price + ", Coupon=" + coupon + ", lock=" + lock + '}'; } } package imooc4.lock.demo; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Supplier; /** * @Author: Alfred * @ModuleOwner: Alfred * @Description: * * * * class CachedData { * Object data; * boolean cacheValid; * final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); * * void processCachedData() { * rwl.readLock().lock(); * if (!cacheValid) { * // Must release read lock before acquiring write lock * rwl.readLock().unlock(); * rwl.writeLock().lock(); * try { * // Recheck state because another thread might have * // acquired write lock and changed state before we did. * if (!cacheValid) { * data = ...; * cacheValid = true; * } * // Downgrade by acquiring read lock before releasing write lock * rwl.readLock().lock(); * } finally { * rwl.writeLock().unlock(); // Unlock write, still hold read * } * } * * try { * use(data); * } finally { * rwl.readLock().unlock(); * } * } * }} */ public class CachedData<T> { T data; boolean cacheValid; final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void setCacheValid(boolean cacheValid) { this.cacheValid = cacheValid; } /** * 查询缓存或者设置缓存 * 如果缓存有效,则使用缓存 */ public T processCachedData(Supplier<T> supplier){ readWriteLock.readLock().lock(); //如果缓存有效就读 //如果缓存失效,则写 if(!cacheValid){ //必须先解锁在加锁 readWriteLock.readLock().unlock(); readWriteLock.writeLock().lock(); //更新缓存 try { if(!cacheValid){ data = supplier.get(); cacheValid = true; } //锁降级开始 //没有释放锁,这个锁会和其他写线程阻塞,为了保护 ---System.out.println(data); readWriteLock.readLock().lock(); }finally { readWriteLock.writeLock().unlock(); } } try { //使用缓存 return data; }finally { readWriteLock.readLock().unlock(); } } } package imooc4.lock.demo; import org.junit.Test; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** * @Description: 商品上架,更新,下架业务 */ public class ProductService { //商品信息缓存 productName -> CachedData Map<String,CachedData<Product>> map = new ConcurrentHashMap<>(); Map<String,Product> mockDataBase = new HashMap<>(); @Test public void TestCache(){ CachedData<Product> cachedData = new CachedData<Product>(); String productName = "trunk"; Product product = cachedData.processCachedData(() -> new Product(productName, 200, 150)); map.put(productName,cachedData); product.updateProductInfo(150,100); cachedData.setCacheValid(false); //从db查询数据 Product product1 = cachedData.processCachedData(this::queryDataFromDb); System.out.println(product1); } @Test public void testProduct() throws InterruptedException { new Thread(this::saveProduct).start(); Thread.sleep(50); final String productName = "trunk"; //下单线程1 new Thread(()->{ Product product = queryProduct(productName); if(Objects.nonNull(product)){ System.out.println("用户拿着这个"+product.getName()+"下单了,价格:"+product.getPrice()+ "赠送优惠券"+product.getCoupon()); } }).start(); Thread.sleep(50); //更新商品 new Thread(()->updateProduct(productName)).start(); Thread.sleep(50); //模拟并发写缓存 //多个线程同时下单 //下单线程2 new Thread(()->{ Product product = queryProduct(productName); if(Objects.nonNull(product)){ System.out.println("用户拿着这个"+product.getName()+"下单了,价格:"+product.getPrice()+ "赠送优惠券"+product.getCoupon()); } }).start(); //下单线程3 new Thread(()->{ Product product = queryProduct(productName); if(Objects.nonNull(product)){ System.out.println("用户拿着这个"+product.getName()+"下单了,价格:"+product.getPrice()+ "赠送优惠券"+product.getCoupon()); } }).start(); while (true){ } } /** * 商品上架 (保存商品) * @return */ public int saveProduct(){ String productName = "trunk"; Product product = new Product(productName,200,150); //保存数据到数据库 mockDataBase.put(productName,product); return 1; } /** * 查询商品信息 * @param productName * @return */ public Product queryProduct(String productName){ CachedData<Product> cacheData = getCacheData(productName); return cacheData.processCachedData(()->mockDataBase.get(productName)); } private CachedData<Product> getCacheData(String productName) { // //操作1 // CachedData<Product> cachedData = map.get(productName); // if(cachedData==null){ // map.put(productName,new CachedData<>()); // } //操作2 return map pute(productName, (k, v) -> { if (v == null) { return new CachedData<>(); } else { return v; } }); } /** * 更新商品 * @param productName * @return */ public int updateProduct(String productName){ Product product = queryProduct(productName); if(Objects.isNull(product)){ return 0; } product.updateProductInfo(150,100); mockDataBase.put(productName,product); CachedData<Product> cacheData = getCacheData(productName); cacheData.setCacheValid(false); map.put(productName,cacheData); return 1; } /** * 商品下架 * @return */ public int deleteProduct(String productName){ //查询商品 Product product = queryProduct(productName); if(Objects.isNull(product)){ return 0; } mockDataBase.remove(productName); map.remove(productName); return 1; } private Product queryDataFromDb() { return new Product("trunk",150,100); } } package imooc4.lock.demo; /** * @Description: */ public class TestProduct { public static void main(String[] args) throws InterruptedException { Product product = new Product("拉杆箱",200,150); System.out.println(product); Thread writeThread = new Thread(()->{ product.updateProductInfo(150,100); }); Thread readThread = new Thread(() -> { double price = product.getPrice(); double coupon = product.getCoupon(); System.out.println(price); System.out.println(coupon); }); writeThread.start(); Thread.sleep(500); readThread.start(); // System.out.println(product); } } 9.(共享锁)信号量Semaphore的应用场景

参考:Java并发神器Semaphore全方位解析_java semaphore-CSDN博客

实现限流器逻辑:

package imooc4.semaphore; import java.util.concurrent.Semaphore; import java.util.function.Supplier; /** * @Description:使用semaphore实现限流功能 */ public class LimitedTask<T> implements Runnable{ private String name; private Semaphore semaphore; private Supplier<T> supplier; public LimitedTask(String name, Semaphore semaphore,Supplier<T> supplier) { this.name = name; this.semaphore = semaphore; this.supplier = supplier; } @Override public void run() { try { //请求许可,如果许可不足,会被阻塞直到有可用的许可 semaphore.acquire(); System.out.println(name+" 正在执行"); supplier.get(); System.out.println(name+" 执行结束"); } catch (InterruptedException e) { throw new RuntimeException(e); }finally { semaphore.release(); } } } package imooc4.semaphore; import java.util.concurrent.Semaphore; /** * @Description: */ public class TestLimitedTask { public static void main(String[] args) { int maxTaskCount = 2; Semaphore semaphore = new Semaphore(maxTaskCount); //启动多个线程,交给LimitedTask去执行 for (int i = 0; i <= 5; i++) { String taskName = "Task "+i; Thread thread = new Thread(new LimitedTask(taskName, semaphore,()->{ //下单的逻辑 try { Thread.sleep(5000); } catch (InterruptedException e) { throw new RuntimeException(e); } return taskName; })); thread.start(); } } }

运行结果:

实现资源池逻辑:

package imooc4.semaphore; import java.util.concurrent.Semaphore; /** * @Description: */ public class ObjectPool<T> { //资源池大小 private final int poolSize; //semaphore大小跟资源池大小一样 private final Semaphore semaphore; //对象都有哪些 private final T[] objects; //对象是否使用 private final boolean[] isUsed; public ObjectPool( T[] objects) { this.poolSize = objects.length; this.semaphore = new Semaphore(poolSize); this.objects = objects; this.isUsed = new boolean[poolSize]; } //获取许可 public T acquire() throws InterruptedException { //拿到许可后获取对象池中的对象 semaphore.acquire(); return getObject(); } //释放许可 public void release(T obj){ if(returnObject(obj)){ semaphore.release(); } } private synchronized boolean returnObject(T obj) { for (int i = 0; i < poolSize; i++) { if(objects[i]==obj&&isUsed[i]){ isUsed[i] = false; return true; } } return false; } private synchronized T getObject() { for (int i = 0; i < poolSize; i++) { if(!isUsed[i]){ isUsed[i] = true; return objects[i]; } } return null; } } package imooc4.semaphore; /** * @Description:测试对象池 */ public class TestObjectPool { public static void main(String[] args) { Integer[] poolObjects = new Integer[]{1,2,3,4,5}; ObjectPool<Integer> objectPool = new ObjectPool<>(poolObjects); //创建多个线程获取对象池中的对象 for (int i = 0; i < 7; i++) { new Thread(()->{ try { Integer obj = objectPool.acquire(); if(obj!=null){ System.out.println(Thread.currentThread().getName()+" 获取到了: "+ obj); Thread.sleep(3000); objectPool.release(obj); }else{ System.out.println(Thread.currentThread().getName()+"对象池耗尽"); } } catch (InterruptedException e) { throw new RuntimeException(e); } }).start(); } } }

运行结果:

 

10.(死锁):什么是死锁?如何排查死锁问题?

演示代码:

package imooc4.lock.deadlock; /** * @Description: */ public class TestDeadLock { public static void main(String[] args) { Object lock = new Object(); Object lock1 = new Object(); new Thread(()->{ synchronized (lock){ try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (lock1){ System.out.println("拿到锁"); } } }).start(); new Thread(()->{ synchronized (lock1){ try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } synchronized (lock){ System.out.println("拿到锁"); } } }).start(); } }

运行结果:

结论:

        两个线程一直没有停止。

通过JVM命令查看:

在真实的业务中死锁一般不容易察觉!

代码示例:

package imooc4.lock.deadlock; /** * @Description: */ public class Coupon { private String id; private String displayName; private Long amount; private Member member; public synchronized Long getAmount(){ return this.amount; } public synchronized void setAmount(Long amount) throws InterruptedException { this.amount = amount; if(amount==0){ Thread.sleep(1000); //从member移除这个优惠券 member.removeCoupon(id); } } public String getId() { return id; } public Coupon(String id, String displayName, Long amount, Member member) { this.id = id; this.displayName = displayName; this.amount = amount; this.member = member; } } package imooc4.lock.deadlock; import java.util.ArrayList; import java.util.List; /** * @Description: */ public class Member { private String id; private String name; private String address; private List<Coupon> coupons; public synchronized void removeCoupon(String id) { this.coupons.removeIf(coupon -> id.equals(coupon.getId())); } public String getId() { return id; } public synchronized Long getAllCouponsAmount() throws InterruptedException { Long result = 0L; Thread.sleep(1000); for (Coupon coupon : coupons) { result+=coupon.getAmount(); } return result; } public Member(String id, String name, String address) { this.id = id; this.name = name; this.address = address; } public void setCoupons(List<Coupon> coupons) { this.coupons = coupons; } } package imooc4.lock.deadlock; import java.util.ArrayList; import java.util.List; /** * @Description: */ public class TestMember { public static void main(String[] args) throws InterruptedException { //构建对象 Member member = new Member("1","慕课","北京"); Coupon coupon = new Coupon("1","coupon1",200L,member); Coupon coupon1 = new Coupon("2","coupon2",150L,member); Coupon coupon2 = new Coupon("3","coupon3",100L,member); List<Coupon> couponList = new ArrayList<>(); couponList.add(coupon); couponList.add(coupon1); couponList.add(coupon2); member.setCoupons(couponList); Thread thread = new Thread(() -> { try { coupon.setAmount(0L); } catch (InterruptedException e) { throw new RuntimeException(e); } }); Thread thread1 = new Thread(() -> { try { Long allCouponsAmount = member.getAllCouponsAmount(); } catch (InterruptedException e) { throw new RuntimeException(e); } }); thread.start(); thread1.start(); thread.join(); thread1.join(); System.out.println("运行结束"); } }

11.(死锁)形成死锁的条件与如何避免死锁?

优化代码:

package imooc4.lock.deadlock; /** * @Description: */ public class Coupon { private String id; private String displayName; private Long amount; private Member member; public synchronized Long getAmount(){ return this.amount; } public void setAmount(Long amount) throws InterruptedException { synchronized(this){ this.amount = amount; } if(amount==0){ Thread.sleep(1000); //从member移除这个优惠券 member.removeCoupon(id); } } public String getId() { return id; } public Coupon(String id, String displayName, Long amount, Member member) { this.id = id; this.displayName = displayName; this.amount = amount; this.member = member; } } package imooc4.lock.deadlock; import java.util.ArrayList; import java.util.List; /** * @Description: */ public class Member { private String id; private String name; private String address; private List<Coupon> coupons; public synchronized void removeCoupon(String id) { this.coupons.removeIf(coupon -> id.equals(coupon.getId())); } public String getId() { return id; } public synchronized Long getAllCouponsAmount() throws InterruptedException { Long result = 0L; Thread.sleep(1000); List<Coupon> temps = new ArrayList<>(coupons); for (Coupon coupon : temps) { result+=coupon.getAmount(); } return result; } public Member(String id, String name, String address) { this.id = id; this.name = name; this.address = address; } public void setCoupons(List<Coupon> coupons) { this.coupons = coupons; } } package imooc4.lock.deadlock; import java.util.ArrayList; import java.util.List; /** * @Description: */ public class TestMember { public static void main(String[] args) throws InterruptedException { //构建对象 Member member = new Member("1","慕课","北京"); Coupon coupon = new Coupon("1","coupon1",200L,member); Coupon coupon1 = new Coupon("2","coupon2",150L,member); Coupon coupon2 = new Coupon("3","coupon3",100L,member); List<Coupon> couponList = new ArrayList<>(); couponList.add(coupon); couponList.add(coupon1); couponList.add(coupon2); member.setCoupons(couponList); Thread thread = new Thread(() -> { try { coupon.setAmount(0L); } catch (InterruptedException e) { throw new RuntimeException(e); } }); Thread thread1 = new Thread(() -> { try { Long allCouponsAmount = member.getAllCouponsAmount(); } catch (InterruptedException e) { throw new RuntimeException(e); } }); thread.start(); thread1.start(); thread.join(); thread1.join(); System.out.println("运行结束"); } }

 运行结果:

12.(活锁)什么是活锁与如何避免活锁的发生? 

活锁是为了解决死锁问题才发生的!

活锁能解决大部分死锁问题,但是极端情况,刚开始所有人左手拿餐叉,等待10秒后,所有人都放弃左手拿餐叉,都改为右手拿餐叉,结果又导致互斥。

标签:

三、Java中七大常用锁实战由讯客互联游戏开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“三、Java中七大常用锁实战