三、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.compute(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.compute(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秒后,所有人都放弃左手拿餐叉,都改为右手拿餐叉,结果又导致互斥。