1.不加锁达不到下要的结果,num最后总有丢掉
package com.mxy.epe.redislock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class TestRedisLocker implements Runnable {
private static final int count = 500;
private static CountDownLatch latch = new CountDownLatch(count);
private static long num = 0;
private static AtomicInteger atomici = new AtomicInteger(0);
public static void main(String[] args) {
TestRedisLocker j = new TestRedisLocker();
long stime = System.currentTimeMillis();
for (int i = 0; i < count ; i++) {
new Thread(j).start();
}
try {
latch.await();
System.out.println(num + "::" + atomici.get());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println((System.currentTimeMillis() - stime));
}
public void run() {
for (int i = 0; i < 3; i++) {
num += 1;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
atomici.getAndIncrement();
latch.countDown();
}
}
2.代码锁
ReentrantLock或synchronized解决单进程的资源安全问题,效率会比分布式锁高,缺点除单进程外还不容易做到指定某个条件。
package com.mxy.epe.redislock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class TestRedisLocker implements Runnable {
private static final int count = 500;
private static CountDownLatch latch = new CountDownLatch(count);
private static long num = 0;
private static AtomicInteger atomici = new AtomicInteger(0);
public static void main(String[] args) {
TestRedisLocker j = new TestRedisLocker();
long stime = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
new Thread(j).start();
}
try {
latch.await();
System.out.println(num + "::" + atomici.get());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println((System.currentTimeMillis() - stime));
System.out.println(rl.redisson.isShutdown());
}
public void run() {
synchronized(TestRedisLocker.class) {
for (int i = 0; i < 3; i++) {
num += 1;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
atomici.getAndIncrement();
latch.countDown();
}
}
3.Redisson
RedLock能做到我需要的功能,给每个用户一把锁保证其资源安全。
A渠道商的积分余额1000,在同一时间提交20个请求每个消费100积分,在积分为0时必须不能被超支,但是这里只是针对A渠道商的积分,B渠道商可以正常消费他的积分,因此AB需各自的同步锁,RedLock可以很好做到。
分布式锁毕竟还是涉及网络连接,无法做到和代码锁那样的效率。
maven依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.3.2</version>
</dependency>
Redisson实现
package com.mxy.epe.redislock;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import java.util.concurrent.TimeUnit;
/**
*
* Type Name : RedLock
* Description : redlock分布式锁
* Author : ThingLin Create
* Date : 2017年10月26日 Version :
*
* History: (Version) Author Date Annotation
*/
public class RedLock {
private final static String LOCKER_PREFIX = "lock:";
/**
* 加锁等待时长ms
*/
private final long waitTime = 500;
/**
* 默认锁持有时长s
*/
private final int defaultLeaseTime = 1;
private RedissonClient redisson;
public RedLock(String ip,int port,String password) {
Config config = new Config();
config.useSingleServer().setAddress(ip+":"+port).setPassword(password);
redisson = Redisson.create(config);
}
/**
*
* Description :
* Author :ThingLin
* Create Date : 2017年10月27日
* History: (Version) Author Date Annotation
* @param resourceName 资源名称
* @return
* @throws InterruptedException
*/
public boolean lock(String resourceName) throws InterruptedException {
return lock(resourceName, defaultLeaseTime);
}
public boolean lock(String resourceName, long lockTime) throws InterruptedException {
RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);
return lock.tryLock(waitTime, lockTime, TimeUnit.SECONDS);
}
public void unlock(String resourceName) {
RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);
lock.unlock();
}
}
测试使用
package com.mxy.epe.redislock;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class TestRedisLocker implements Runnable {
private static final int count = 500;
private static CountDownLatch latch = new CountDownLatch(count);
private static long num = 0;
private static long sum = 0;
private static AtomicInteger atomici = new AtomicInteger(0);
private static RedLock rl = new RedLock("127.0.0.1", 6379, "123456qq");
public static void main(String[] args) {
TestRedisLocker j = new TestRedisLocker();
long stime = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
Thread thread = new Thread(j);
thread.setName(i + "");
thread.start();
}
try {
latch.await();
System.out.println(sum+"::"+num + "::" + atomici.get());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println((System.currentTimeMillis() - stime));
}
public void run() {
// 用线程名称模拟下不同用户,在服务生产环境用用户id区别
int threadid = Integer.parseInt(Thread.currentThread().getName());
if (threadid % 2 == 0) {
try {
rl.lock("dddd"); //用户A 的资源锁(resourceName)名称dddd
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
num += 1;
}
rl.unlock("dddd");
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
rl.lock("bbbb");//用户A 的资源锁(resourceName)名称bbbb
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
sum += 1;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
rl.unlock("bbbb");
}
atomici.getAndIncrement();
latch.countDown();
}
}