seo网站推广案例,网站建设服务目标,怎么制作seo搜索优化,镇江网站制作哪家公司比较好什么是分布式锁?
当有多个线程并发访问同一共享数据时,如果多个线程同时都去修改这个共享数据,且修改操作不是原子操作,就很有可能出现线程安全问题#xff0c;而产生线程安全问题的根本原因是缺乏对共享数据访问的同步和互斥。 为了解决这个问题#xff0c;通常我们的做法…
什么是分布式锁?
当有多个线程并发访问同一共享数据时,如果多个线程同时都去修改这个共享数据,且修改操作不是原子操作,就很有可能出现线程安全问题而产生线程安全问题的根本原因是缺乏对共享数据访问的同步和互斥。 为了解决这个问题通常我们的做法是通过加锁来解决该问题,比如ReentrantLock or Synchronized ,但是在分布式系统中,存在多台服务器与客户端,这些节点之间都可能访问相同的共享数据。而Java中的内置锁机制如synchronized和ReentrantLock都是JVM内部的,无法对其他服务器产生效果。因此无法解决真正的分布式多线程访问安全问题。为了实现分布式环境下的线程安全,需要引入外部的协调组件,实现一个分布式锁常见的分布式锁组件有Redis、Zookeeper等当然也可以基于数据库的悲观锁或CAS操作实现分布式锁。 传统redis工具类实现分布式锁
通过redis工具类基于实现分布式锁。
/**
* 加锁
*
* param key - key名称
* param expireMillisecond - 锁成功后的有效期,毫秒
* return return null or empty string is lock failed Otherwise return uuid value of lock-key
*/
public String lock(String key, long expireMillisecond) {Preconditions.checkArgument(StringUtils.isNotBlank(key));Preconditions.checkArgument(expireMillisecond 0L);String lockKey LOCK_KEY_PREFIX key;String lockValue UUID.randomUUID().toString();boolean keySet redisTemplateWarpper.vSetIfAbsent(lockKey, lockValue, expireMillisecond);if (keySet) { //锁成功return lockValue;}return null;
}/**
* 解锁
*
* param key
*/
public void unlock(String key, String value) {if (StringUtils.isBlank(value)) {return;}String lockKey LOCK_KEY_PREFIX key;String lockValueRedis redisTemplateWarpper.vGet(lockKey);if (StringUtils.equals(lockValueRedis, value)) {redisTemplateWarpper.kDelete(lockKey);}
}public Boolean vSetIfAbsent(String key, String value, long timeoutMillisecond) {RedisSerializerString stringSerializer stringRedisTemplate.getStringSerializer();return stringRedisTemplate.execute(new RedisCallbackBoolean() {Overridepublic Boolean doInRedis(RedisConnection connection) throws DataAccessException {Object obj connection.execute(set,stringSerializer.serialize(checkKey(key)),stringSerializer.serialize(value),stringSerializer.serialize(NX),stringSerializer.serialize(PX),stringSerializer.serialize(String.valueOf(timeoutMillisecond)));return obj ! null;}});}传统的工具类实现redis分布式锁实现方式简单虽然可以提供分布式锁的效果但实际效果其实并不理想因为在特殊情况下存在种种问题。
死锁问题
业务阻塞死锁 某个客户端在执行一个长时间的阻塞操作例如使用 BLPOP 或 BRPOP 命令来阻塞地等待列表中的元素。如果该操作长时间未完成或未释放连接其他客户端可能无法获取连接导致死锁。
**客户端宕机死锁**客户端在解锁前崩溃下线,未设置过期时间导致锁无法释放。
锁时间不合理问题
在锁资源的时候我们可以给锁设置过期时间但锁的时间过长或过短都会出现问题。例如锁时间过长其他线程一直无法获取锁资源从而阻塞业务不能够正常进行。锁时间过短锁资源中的任务还未执行完毕其他线程已经可以获取到锁资源从而操作共享数据出现线程安全问题。
功能单一问题
仅能提供基础的加锁与解锁的功能高级功能需要自己实现(例如读写锁、公平锁等等)
redisson分布式锁 什么是redisson分布式锁
Redisson是一个在Redis的基础上实现的Java驻内存数据网格In-Memory Data Grid。它不仅提供了一系列的分布式的Java常用对象还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) **
如何解决传统redis工具类问题 死锁问题
解决业务阻塞死锁通过tryLock(long waitTime, TimeUnit unit) 尝试获取锁其他线程一定时间未获取不到锁就返回false停止获取锁。解决客户端宕机死锁不传过期时间时默认会设置30秒的过期时间节点没宕机的情况下如果任务未执行完会持续进行锁续期节点宕机后则不会再进行续期到了过期时间后就会删掉key
锁时间不合理问题
通过看门狗机制自动进行锁续期不进行人工干预。
功能单一问题
不仅提供了一系列的分布式的Java常用对象还提供了许多分布式服务。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最简单和最便捷的方法 redisson加锁流程 看门狗机制 什么是看门狗机制
Redisson提供了一个监控锁的看门狗它的作用是在Redisson实例被关闭前不断的延长锁的有效期也就是说如果一个拿到锁的线程一直没有完成逻辑那么看门狗会帮助线程不断的延长锁超时时间锁不会因为超时而被释放。默认情况下看门狗的续期时间是30s也可以通过修改Config.lockWatchdogTimeout来另行指定。另外Redisson 还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了不会延长锁的有效期。 什么时候会启动看门狗机制
方法描述Watch Dog 延期机制lock()拿锁失败时会不停的重试直到成功获取锁有续锁时间默认为30秒每隔30/310秒续锁tryLock(10, TimeUnit.SECONDS)尝试在10秒内获取锁获取成功返回true失败返回false有续锁时间默认为30秒lock(10, TimeUnit.SECONDS)void lock(long leaseTime, TimeUnit unit);拿锁失败时会不停的重试10秒后自动释放锁无10秒后自动释放锁tryLock(100, 10, TimeUnit.SECONDS)boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) 尝试在100秒内获取锁每次重试间隔为10秒获取成功返回true失败返回false无10秒后自动释放锁
如果你想让Redisson启动看门狗机制你就不能自己在获取锁的时候定义超时释放锁的时间无论是通过lock() **还是通过tryLock获取锁只要在参数中不传入releastime就会开启看门狗机制。**就是这两个方法不要用 boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedExceptionvoid lock(long leaseTime, TimeUnit unit);因为它俩都传release但是你传的leaseTime是-1也是会开启看门狗机制的 看门狗机制源码分析 // 直接使用lock无参数方法
public void lock() {try {lock(-1, null, false);} catch (InterruptedException e) {throw new IllegalStateException();}
}// 进入该方法 其中leaseTime -1
private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {long threadId Thread.currentThread().getId();Long ttl tryAcquire(-1, leaseTime, unit, threadId);// lock acquiredif (ttl null) {return;}//...
}// 进入 tryAcquire(-1, leaseTime, unit, threadId)
private Long tryAcquire(long waitTime, long leaseTime, TimeUnit unit, long threadId) {return get(tryAcquireAsync(waitTime, leaseTime, unit, threadId));
}// 进入 tryAcquireAsync
private T RFutureLong tryAcquireAsync(long waitTime, long leaseTime, TimeUnit unit, long threadId) {RFutureLong ttlRemainingFuture;// leaseTime -1if (leaseTime 0) {ttlRemainingFuture tryLockInnerAsync(waitTime, leaseTime, unit, threadId, RedisCommands.EVAL_LONG);} else {ttlRemainingFuture tryLockInnerAsync(waitTime, internalLockLeaseTime,TimeUnit.MILLISECONDS, threadId, RedisCommands.EVAL_LONG);}CompletionStageLong s handleNoSync(threadId, ttlRemainingFuture);ttlRemainingFuture new CompletableFutureWrapper(s);CompletionStageLong f ttlRemainingFuture.thenApply(ttlRemaining - {// lock acquired leaseTime -1if (ttlRemaining null) {if (leaseTime 0) {internalLockLeaseTime unit.toMillis(leaseTime);} else {// 看门狗续期scheduleExpirationRenewal(threadId);}}return ttlRemaining;});return new CompletableFutureWrapper(f);}protected void scheduleExpirationRenewal(long threadId) {ExpirationEntry entry new ExpirationEntry();ExpirationEntry oldEntry EXPIRATION_RENEWAL_MAP.putIfAbsent(getEntryName(), entry);if (oldEntry ! null) {oldEntry.addThreadId(threadId);} else {entry.addThreadId(threadId);try {renewExpiration();} finally {if (Thread.currentThread().isInterrupted()) {cancelExpirationRenewal(threadId);}}}}private void renewExpiration() {ExpirationEntry ee EXPIRATION_RENEWAL_MAP.get(getEntryName());if (ee null) {return;}Timeout task commandExecutor.getServiceManager().newTimeout(new TimerTask() {Overridepublic void run(Timeout timeout) throws Exception {ExpirationEntry ent EXPIRATION_RENEWAL_MAP.get(getEntryName());if (ent null) {return;}Long threadId ent.getFirstThreadId();if (threadId null) {return;}CompletionStageBoolean future renewExpirationAsync(threadId);future.whenComplete((res, e) - {if (e ! null) {log.error(Cant update lock {} expiration, getRawName(), e);EXPIRATION_RENEWAL_MAP.remove(getEntryName());return;}if (res) {// reschedule itselfrenewExpiration();} else {cancelExpirationRenewal(null);}});}// 默认锁租期internalLockLeaseTime 30s 默认续期时间为锁租期/3 10s}, internalLockLeaseTime / 3, TimeUnit.MILLISECONDS);ee.setTimeout(task);}