1. 为什么需要锁在并发场景下,多个进程/线程同时对同一个资源进行访问时,会产生冲突 。
举个例子:核酸采样时,如果一次100个人同时要求大白进行采样(并发),那么大白就要崩溃了,所以必须要控制一个大白一次只能对一个人采样,其他人等待采样完成,这就是对大白进行”加锁” 。
2. 锁是用来解决什么问题的锁是用来解决并发问题的,如:
- 多个线程并发访问同一个资源
- 分布式系统中不同模块对同一资源进行修改
- 秒杀
- 抢红包
- 库存更新
- 通过数据库实现(利用数据库唯一约束的特性实现)
- 通过Zookeeper实现(利用zookeeper的唯一节点特性或者有序临时节点特性获得最小节点作为锁)
- 通过redis实现(setNx命令)
redis.clients.jedis.exceptions.JedisConnectionException: Failed to connect to any host resolved for DNS name.at redis.clients.jedis.DefaultJedisSocketFactory.connectToFirstSuccessfulHost(DefaultJedisSocketFactory.java:63)at redis.clients.jedis.DefaultJedisSocketFactory.createSocket(DefaultJedisSocketFactory.java:87)at redis.clients.jedis.Connection.connect(Connection.java:180)at redis.clients.jedis.Connection.initializeFromClientConfig(Connection.java:338)可能有如下原因:- Redis未启动
- Redis IP地址或者端口不对
- Redis不允许远程连接
//查看6379端口状态 mo表示未开放[root@192 bin]# firewall-cmd --zone=public --query-port=6379/tcp no//配置放行6379端口[root@192 bin]# firewall-cmd --zone=public --add-port=6379/tcp --permanentsuccess//防火墙重载[root@192 bin]#firewall-cmd --reloadsuccess//再次查看端口状态[root@192 bin]# firewall-cmd --zone=public --query-port=6379/tcpyes4.1.2 修改redis.conf配置文件[root@192 redis]# vim redis.conf将配置改成如下所示:
# 允许任何主机连接、访问bind 0.0.0.0# 关闭保护模式protected-mode no# 允许启动后在后台运行,即关闭命令行窗口后仍能运行daemonize yes4.2 模拟秒杀下单减库存的场景4.2.1 新建以下商品表(t_goods)与订单表(t_order)DROP TABLE IF EXISTS `t_goods`;CREATE TABLE `t_goods` (`id` int(11) NOT NULL,`name` varchar(60) DEFAULT NULL,`qty` int(11) DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;--初始化数量qty=20INSERT INTO `t_goods` VALUES ('1', '华为nova7', '20');DROP TABLE IF EXISTS `t_order`;CREATE TABLE `t_order` (`oid` varchar(120) NOT NULL,`createtime` datetime DEFAULT NULL,`goodname` varchar(255) DEFAULT NULL,`user` varchar(120) DEFAULT NULL,PRIMARY KEY (`oid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;4.2.2 编写main方法,同时启动10000条线程模拟秒杀【分布式锁的实现方式】public static void main(String[] args) throws ParseException {//设置秒杀开始时间String startTime="2022-4-27 23:24:00";SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date start=simpleDateFormat.parse(startTime);System.out.println("等待中...");boolean isStart=false;while (!isStart) {if (start.compareTo(new Date()) < 0) {isStart=true;System.out.println("秒杀开始...");//同时启动10000条线程CountDownLatch countDownLatch = new CountDownLatch(10000);for (int i = 0; i < 10000; i++) {new Thread(() -> {try {countDownLatch.await();//secKillGoodsByRedisLock();//Redis锁secKillGoods();//未加锁// secKillGoodsByLock();//synchronized} catch (InterruptedException | SQLException e) {e.printStackTrace();}}).start();countDownLatch.countDown();}}}}4.2.3 未加锁的情况private static void secKillGoods() throws SQLException {List list = DButil.query("select id,name,qty from t_goods where id=1 and qty>0");//判断是否还有库存if(list.size()>0){String id=JedisUtil.getId();Object[] insertObject={id,new Date(),"nova7",Thread.currentThread().getName()};DButil.excuteDML("update t_goods set qty=qty-1 where id=1 ");DButil.excuteDML("insert into t_order values(?,?,?,?);",insertObject);System.out.println(Thread.currentThread().getName()+">>>抢到了."+id);}}以上代码每次执行都会先判断是否还有库存,如果有库存则秒杀成功,否则秒杀失败,没有并发的情况下是可以正常运行的,但是一旦存在并发,则会出现负库存(超卖)推荐阅读
- Docker私有仓库Registry删除镜像的方法
- 滇红茶有黑色的,红茶的泡多长时间
- 崂山红茶泡茶时间,崂山红茶的保质期
- 泡红茶的茶具名称,金骏茶的功效与作用
- 蜜糖泡红茶,蜜糖红茶
- 红茶泡蜂蜜的功效,红茶是否可以加蜂蜜
- 祁门红茶泡后,祁门红茶有什么好处
- 红茶种子是怎么样的,祁红红茶怎么泡
- 很细的红茶叶,藏红花枸杞茶的泡法
- 杜仲和红茶怎么泡,杜仲肉苁蓉茶的功效与作用
