Java中锁的应用

文章目录

  • 前言
  • 一、场景描述
  • 二、加锁
    • 1.synchronized
    • 2.ReentrantLock
  • 三、扩展
    • 1.ThreadLocal
  • 总结


前言

在多线程场景下,多个线程同时对共享变量进行操作是存在风险的,这时候就需要加锁来保证数据的正确性。


一、场景描述

我这里有5个无人机,准备卖到乌克兰,奈何买家太多了,应酬不来,就挂到了网上,先到先得。

卖方

@Controller
public class StudentLockController {
    private static int number=5;
    public boolean get(){
        String name = Thread.currentThread().getName();
        if(number>0){
            try {
                //模拟业务处理时间
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(name+"业务处理成功");
            number--;
            return true;
        }
        System.out.println(name+"业务处理失败");
        return false;
    }
    public int size(){
        return number;
    }
}

买方

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootStart.class)
public class SpringbootStartTest {
	@Autowired
    private StudentLockController studentLockController;
    @Test
    public void test(){
        normal();
    }
    public void normal(){
        int count=10;
        ExecutorService threadPool = Executors.newFixedThreadPool(count);
        Future<Boolean> submit = null;
        for(int i=0;i<count;i++){
            submit = threadPool.submit(() -> studentLockController.get());
        }
        try {
            submit.get();
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
        System.out.println("数量:"+studentLockController.size());
        threadPool.shutdown();
    }
}

来了10个买家,都抢上了,这库存就5个了肯定不够,这样不行,得重新抢,我加个锁让他们排队去
Java中锁的应用_第1张图片

二、加锁

1.synchronized

public synchronized boolean get(){
        String name = Thread.currentThread().getName();
        if(number>0){
            try {
                //模拟业务处理时间
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(name+"业务处理成功");
            number--;
            return true;
        }
        System.out.println(name+"业务处理失败");
        return false;
    }

Java中锁的应用_第2张图片
给这个方法加个锁,但这个锁范围太大了,导致我库存没卖完,这不耽误挣钱了嘛,那哪行,继续改。

2.ReentrantLock

@Controller
public class StudentLockController {
    private static int number=5;
    private ReentrantLock rl=new ReentrantLock();
    public boolean get(){
        String name = Thread.currentThread().getName();
        while (!rl.tryLock()){
            try {
                //获取锁等待时间
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        try {
            if(number>0){
                //模拟业务处理时间
                Thread.sleep(1000);
                System.out.println(name+"业务处理成功");
                number--;
                return true;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            if(rl.isLocked()){
                rl.unlock();
            }
        }
        System.out.println(name+"业务处理失败");
        return false;
    }
    public int size(){
        return number;
    }
}

Java中锁的应用_第3张图片
嗯,东西都卖出去了,没货了就失败了,这个能挣大钱了,ReentrantLock这个好

三、扩展

每个买家购买物品之前需要登陆,一个买家账户会开启一个专门的线程来维护,买家有3次用户名、密码失败的次数,这就需要控制每个线程拥有单独的变量,ThreadLocal可以为每个线程开辟单独的工作空间。

1.ThreadLocal

    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
    threadLocal.set(0);
    Integer count = threadLocal.get();
    if(count >=3){
    	System.out.println("已经达到最大重试次数,请联系管理员进行重置!");
    }
    threadLocal.remove();

总结

回到顶部
加锁是为了保证多线程下数据的安全,但是锁过多和范围过大会影响程序性能,增加服务的处理时间,所以,使用锁要考虑当前的业务场景是否合适。

你可能感兴趣的:(java,开发语言)