Blog index
There is a redis de-weight scenario. The business code was as follows:
Public void handle(String key){if(redis.sismember("myset",key)){return; }else{redis. Sadd ("myset",key); } // Business codeCopy the code
The pseudocode says: If the element key already exists in the collection, return it; If not, the element key is added to the collection mySet to execute the business code.
At first glance, this doesn’t seem to be a problem, but because of the concurrency, it can cause the business code to execute repeatedly.
Suppose two threads call handle at the same time with the entry key 007. The execution sequence is as follows:
Thread a | Thread 2 |
---|---|
Redis. Sismember (” myset, “key) returns false | |
switch | Redis. Sismember (” myset, “key) returns false |
Perform redis. Sadd (” myset “, 007); | |
switch | |
Perform redis. Sadd (” myset “, 007); | |
Execute business code | |
Execute business code |
When thread 1 calls redis.sismember(“myset”,key), there is no 007 in the set, return false, jump to else. At this point thread 1 runs out of time slice, switch to thread 2.
Sadd (“myset”,key); sadd(“myset”,key); sadd(“myset”,key); Thread 2 then switches to thread 1 again, and thread 1 continues down sadd(“myset”,key) to add the 007 element.
This is where the business code is executed multiple times, resulting in data problems.
Although the single redis command guarantees atomicity, the “put-if-Absent” operation in the pseudocode above has a race condition. Although the atomicity of the method can be guaranteed by locking it,
But since we’re using Redis, and redis happens to provide an atomic command setnx key Value, if there’s no key, set it, if there is, do nothing; So all you need to do here is change the pseudocode.
Public void handle(String key){if(! redis.setnx(key,0)){ return; } // Business codeCopy the code
That leaves the question of how to change the collection to a thread-safe vector.