当前位置: 首页 > news >正文

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

相关文章:

  • firefox的升级
  • 机器学习:k近邻
  • MySQL 联合索引的最左匹配原则
  • pandas(12 IO工具和稀松数据)
  • 算法题(69):搜索插入位置
  • BY组态:构建灵活、可扩展的自动化系统
  • 深入HBase——Bigtable
  • kamailio中Core Cookbook 核心配置手册
  • MVC模式和MVVM模式
  • Linux网络 | 多路转接epoll
  • 动手实现一个PDF阅读器
  • 深度解析前端性能优化:策略与实践
  • 2025年-数据库排名
  • 《红色警戒:兵临城下》 游戏软件安装步骤与百度网盘链接
  • 无题 -- 想做什么
  • unity学习44:学习Animator 的一个动作捕捉网站,实测好用
  • Java + Vosk 开启麦克风离线语音识别新纪元!
  • XXL-Job入门
  • vue+elementplus创建初始化安装
  • 【pytorch】weight_norm和spectral_norm
  • 浙江“胖都来”开业多位明星祝贺,“胖东来”称已取证投诉,律师:碰瓷侵权
  • 澳大利亚大选今日投票:聚焦生活成本与“特朗普问题”
  • 天津航空一航班盘旋14圈才降落,客服:因天气影响
  • 《探秘海昏侯国》数字沉浸特展亮相首届江西文化旅游产业博览交易会
  • 国新办发布《关于新冠疫情防控与病毒溯源的中方行动和立场》白皮书
  • 华夏幸福:去年营业收入237.65亿元,同比减亏12亿元