Inadequate synchronized with the use of distributed lock redis

Here is a simple logic simulation spike, stock and orders for the two Map, simulate inventory list and order form

public  void orderProductMockDiffUser (String productId) 
    { 
        // 1. The merchandise inventory query, is 0 end of the event. 
        int stockNum = stock.get (the productId);
         IF (stockNum == 0 ) {
             the throw  new new SellException (100, "end of the event" ); 
        } the else {
             // 2. Order (to simulate different users different openid) 
            orders.put ( KeyUtil.genUniqueKey (), the productId);
             // 3. Save stock (analog memory (or Redis) Save the stock) 
            stockNum =. 1-stockNum ;
             the try {
                 // 4. mimics some IO operations or other business 
                Thread.sleep ( 100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stock.put(productId,stockNum);
        }
    }

This logic when there is a problem complicated by the large amount of time, the number of inconsistencies number of goods sold and inventory will result subtracted

 

 

 We can use the synchronized keyword to solve this problem, plus synchronized on the method name

public synchronized void orderProductMockDiffUser(String productId)

While the number of synchronized can solve the problem of inconsistency, but the disadvantages are also obvious, and that is slow, because the synchronized modification of the method is synchronous, meaning that only one thread access to this method, and synchronized applies only to a single point.

A better approach is to use distributed lock redis

@Component 
@ SLF4J 
public  class RedisLock { 

    @Autowired 
    Private StringRedisTemplate redisTemplate; 

    / ** 
     * lock 
     * @param Key Product ID 
     * @param value of the current time + timeout 
     * @return 
     * / 
    public  Boolean Lock (String Key, String value) {
         // setIfAbsent () is the redis setnx, set value when the key does not exist 
        iF {(redisTemplate.opsForValue () setIfAbsent (key, value).)
             // locked successfully 
            return  to true ; 
        } 
        // when the lock already exists you can acquire the lock of value, to determine whether expired
        CurrentValue = String redisTemplate.opsForValue () GET (Key);.
         // If the lock expires 
        IF (! StringUtils.isEmpty (currentValue)
                 && Long.parseLong (currentValue) < System.currentTimeMillis ()) {
             // obtaining a lock time 
            String oldValue = redisTemplate.opsForValue () getAndSet (Key, value);.
             // if two threads enter here, may be determined by equality oldValue plurality of threads to limit the currentValue locking 
            IF (StringUtils.isEmpty (! oldValue) && oldValue.equals (currentValue)) {
                 return  to true ; 
            } 
        } 

        return  to false ; 
    }

    /**
     * 解锁
     * @param key
     * @param value
     */
    public void unlock(String key, String value) {
        try {
            String currentValue = redisTemplate.opsForValue().get(key);
            if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e) {
            log.error("【redis分布式锁】解锁异常, {}", e);
        }
    }

}

So long as we add locks to spike when the logical beginning, the end of the logic unlock it. redis than synchronized distributed lock not only faster, but also for distributed.

 public  void orderProductMockDiffUser (String the productId) 
    { 
        // lock 
        Long Time = System.currentTimeMillis () + TIMEOUT;
         IF (! redisLock.lock (the productId, String.valueOf (Time))) {
             the throw  new new SellException (ResultEnum.REDIS_LOCK_FAIL); 
        } 
        // 1. query the merchandise inventory for 0 end of the event. 
        int stockNum = stock.get (the productId);
         IF (stockNum == 0 ) {
             the throw  new new SellException (100, "end of the event" ); 
        } the else {
             // 2. Order (to simulate different users different openid)
            orders.put (KeyUtil.genUniqueKey (), the productId);
             // 3. Save stock (analog memory (or Redis) Save the stock) 
            stockNum =. 1-stockNum ;
             the try {
                 // 4. mimics some other business operations or IO 
                thread.sleep (100 ); 
            } the catch (InterruptedException E) { 
                e.printStackTrace (); 
            } 
            stock.put (the productId, stockNum); 
        } 

        // unlock 
        redisLock.unlock (the productId, String.valueOf (Time)); 
    }

 

Guess you like

Origin www.cnblogs.com/skychmz/p/11498782.html