赞
踩
单体应用多线程锁
使用synchronized关键字或ReentrantLock类来保证线程的顺序执行
个别场景使用JDK1.5之后提供的大量原子类AtomicInteger(基于CAS的乐观锁)
测试锁模拟并发可使用闭锁:CountDownLatch类对象模拟
ReentrantLock的公平锁和非公平锁机制
ReentrantLock有两个构造方法,默认的构造方法中,
sync = new NonfairSync();
我们可以从字面意思看出它是一个非公平锁。再看看第二个构造方法,它需要传入一个参数,参数是一个布尔型,true
是公平锁,false
是非公平锁。从上面的源码我们可以看出sync
有两个实现类,分别是FairSync
和NonfairSync;
唯一的不同之处在于!hasQueuedPredecessors()
这个方法,很明显这个方法是一个队列,由此可以推断,公平锁是将所有的线程放在一个队列中,一个线程执行完成后,从队列中取出下一个线程,而非公平锁则没有这个队列。这些都是公平锁与非公平锁底层的实现原理。
- //基于原子类(乐观锁)
- public class Test {
-
- private AtomicInteger i = new AtomicInteger(0);
- public static void main(String[] args) {
- Test test = new Test();
- ExecutorService es = Executors.newFixedThreadPool(50);
- CountDownLatch cdl = new CountDownLatch(5000);
- for (int i = 0;i < 5000; i++){
- es.execute(()->{
- test.i.incrementAndGet();
- cdl.countDown();
- });
- }
- es.shutdown();
- try {
- cdl.await();
- System.out.println("执行完成后,i="+test.i);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
- //基于synchronized (悲观锁)
- //使用CountDownLatch模拟并发
- public class Test {
-
- private int i=0;
- public static void main(String[] args) {
- Test test = new Test();
- ExecutorService es = Executors.newFixedThreadPool(50);
- CountDownLatch cdl = new CountDownLatch(5000);
- for (int i = 0;i < 5000; i++){
- es.execute(()->{
- //修改部分 开始
- synchronized (test){
- test.i++;
- }
- //修改部分 结束
- cdl.countDown();
- });
- }
- es.shutdown();
- try {
- cdl.await();
- System.out.println("执行完成后,i="+test.i);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
-
-
-
- //基于ReentrantLock(悲观锁)
- //使用CountDownLatch模拟并发
- public class test {
- private int i=0;
- Lock lock = new ReentrantLock();
- public static void main(String[] args) {
- test test = new test();
- //线程池:50个线程
- ExecutorService es = Executors.newFixedThreadPool(50);
- //闭锁
- CountDownLatch cdl = new CountDownLatch(5000);
- for (int i = 0;i < 5000; i++){
- es.execute(()->{
- test.lock.lock();
- test.i++;
- test.lock.unlock();
- cdl.countDown();
- });
- }
- es.shutdown();
- try {
- //等待5000个任务执行完成后,打印出执行结果
- cdl.await();
- System.out.println("执行完成后,i="+test.i);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
分布式多线程锁
实现方式,一半基于第三方,如:数据库加锁,redis的单线程特性,zk,redisson分布式锁
1.基于mysql数据库sql特性 select.....for update 行锁(排它锁),高并发不适用,数据库压力大
2.redis分布式锁,代码示例如下:
- //公共类,锁工具
- //AutoCloseable 自动关闭资源
- @Slf4j
- public class RedisLock implements AutoCloseable {
-
- private RedisTemplate redisTemplate;
- private String key;
- private String value;
- //单位:秒
- private int expireTime;
-
- public RedisLock(RedisTemplate redisTemplate,String key,int expireTime){
- this.redisTemplate = redisTemplate;
- this.key = key;
- this.expireTime=expireTime;
- this.value = UUID.randomUUID().toString();
- }
-
- /**
- * 获取分布式锁
- * @return
- */
- public boolean getLock(){
- RedisCallback<Boolean> redisCallback = connection -> {
- //设置NX
- RedisStringCommands.SetOption setOption = RedisStringCommands.SetOption.ifAbsent();
- //设置过期时间
- Expiration expiration = Expiration.seconds(expireTime);
- //序列化key
- byte[] redisKey = redisTemplate.getKeySerializer().serialize(key);
- //序列化value
- byte[] redisValue = redisTemplate.getValueSerializer().serialize(value);
- //执行setnx操作
- Boolean result = connection.set(redisKey, redisValue, expiration, setOption);
- return result;
- };
-
- //获取分布式锁
- Boolean lock = (Boolean)redisTemplate.execute(redisCallback);
- return lock;
- }
-
- public boolean unLock() {
- String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
- " return redis.call(\"del\",KEYS[1])\n" +
- "else\n" +
- " return 0\n" +
- "end";
- RedisScript<Boolean> redisScript = RedisScript.of(script,Boolean.class);
- List<String> keys = Arrays.asList(key);
-
- Boolean result = (Boolean)redisTemplate.execute(redisScript, keys, value);
- log.info("释放锁的结果:"+result);
- return result;
- }
-
-
- @Override
- public void close() throws Exception {
- unLock();
- }
- }
-
-
-
- //可起多应用多线程测试
- //try(){}catch(){} 新特性
- //AutoCloseable 自动关闭资源
- @Service
- @Slf4j
- public class SchedulerService {
- @Autowired
- private RedisTemplate redisTemplate;
-
- @Scheduled(cron = "0/5 * * * * ?")
- public void sendSms(){
- try(RedisLock redisLock = new RedisLock(redisTemplate,"autoSms",30)) {
- if (redisLock.getLock()){
- log.info("向138xxxxxxxx发送短信!");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- }
Redisson分布式锁
- //引入依赖jar包
- //<dependency>
- // <groupId>org.redisson</groupId>
- // <artifactId>redisson</artifactId>
- // <version>3.11.2</version>
- //</dependency>
-
- //<dependency>
- // <groupId>org.redisson</groupId>
- // <artifactId>redisson-spring-boot-starter</artifactId>
- // <version>3.17.0</version>
- //</dependency>
-
- //简单一个请求方法示例
- @RestController
- @Slf4j
- public class RedissonLockController {
- @Autowired
- private RedissonClient redisson;
-
- @RequestMapping("redissonLock")
- public String redissonLock() {
- //获取锁
- RLock rLock = redisson.getLock("order");
- log.info("我进入了方法!!");
- try {
- //加锁,设置过期时间
- rLock.lock(30, TimeUnit.SECONDS);
- log.info("我获得了锁!!!");
- Thread.sleep(10000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally {
- log.info("我释放了锁!!");
- rLock.unlock();
- }
- log.info("方法执行完成!!");
- return "方法执行完成!!";
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。