随着用户的增加,并发现象出现的频率越来越多 ,这时候如果没有做好并发处理 ,会造成数据的不一致,然后就需要增加一下锁,需要不同的用户 在 同一时间 仅能对一个 对象进行操作,为了 更好的拓展性,自己写了个类,用于来管理 并发请求,具体得逻辑 就是 每一个请求过来 获取唯一键值的对象,保证对于同一键值处理的请求获取到的是同一个对象,然后在对同一个对象其进行相关操作时,仅能一条一条处理,用synchronized关键字来限制即可,大概画了一下原理图,每根线对应一个 请求,用完之后将其释放
下面是这个管理类的实现代码:
package com.mx.util;
import java.util.HashMap;
public class MxObjectLockUtil {
private HashMap<String,PlanLock> planLockHashMap = new HashMap<>(40);
private static volatile MxObjectLockUtil instance;
private MxObjectLockUtil(){
}
public HashMap<String, PlanLock> getPlanLockHashMap() {
return planLockHashMap;
}
public synchronized PlanLock getObjectLock(String key){
if (planLockHashMap.get(key) == null){
PlanLock planLock = new PlanLock();
planLockHashMap.put(key,planLock);
System.err.println("生成:" + key);
return planLock;
}
return planLockHashMap.get(key);
}
public void removeLock(String key){
if (planLockHashMap.get(key) != null){
PlanLock planLock = planLockHashMap.remove(key);
System.err.println("移除:" + key + ";对象:" + planLock);
}
}
public static MxObjectLockUtil getInstance(){
if (instance == null){
synchronized (MxObjectLockUtil.class){
if (instance == null){
instance = new MxObjectLockUtil();
}
}
}
return instance;
}
class PlanLock{
public synchronized void run(Runnable runnable){
runnable.run();
}
}
}
然后写了个测试类,看效果
package com.mx.util;
import java.util.Random;
public class Test {
public static MxObjectLockUtil mxObjectLockUtil;
public static void main(String[] args) {
mxObjectLockUtil = MxObjectLockUtil.getInstance();
Random random = new Random();
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
String key = random.nextInt(1) + "";
mxObjectLockUtil.getObjectLock(key).execute(new sleepRunabble(key, 400));
mxObjectLockUtil.removeLock(key);
}
}).start();
}
}
static class sleepRunabble implements Runnable {
private String id;
private long times;
sleepRunabble(String id, long times) {
this.id = id;
this.times = times;
}
@Override
public void run() {
System.out.println("我是" + id);
try {
Thread.sleep(times);
System.out.println(id + "延迟" + times + "ms");
System.err.println(mxObjectLockUtil.getPlanLockHashMap().size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这是测试10个线程操作1个对象的时候
正常,并没有出现同时 我是0的编号或同一个编号在延迟,
下面来测试 同时1000个线程,对200个对象操作的情况,测试代码如下:
package com.mx.util;
import java.util.Random;
public class Test {
public static MxObjectLockUtil mxObjectLockUtil;
public static void main(String[] args) {
mxObjectLockUtil = MxObjectLockUtil.getInstance();
Random random = new Random();
for (int i = 0; i < 10000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
String key = random.nextInt(200) + "";
mxObjectLockUtil.getObjectLock(key).execute(new sleepRunabble(key, 50));
mxObjectLockUtil.removeLock(key);
}
}).start();
}
}
static class sleepRunabble implements Runnable {
private String id;
private long times;
sleepRunabble(String id, long times) {
this.id = id;
this.times = times;
}
@Override
public void run() {
System.out.println("我是" + id);
try {
Thread.sleep(times);
System.out.println(id + "延迟" + times + "ms");
System.err.println(mxObjectLockUtil.getPlanLockHashMap().size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
依旧没有同时 同一个编号在延迟或生成的,完全说明了这个方法是可行的,效率也还可以,当10000个对200对象操作请求发来时,差不多平均每50个线程是对同一个对象,这50个对象 依次拿到 同一个对象,然后依次执行 ,主要耗时,仅是,刚开始获取分配对象时,后续基本就是200个不对对象同时操作
如有更好的建议或有误的地方,请评论出来,我也在不断的学习和提升中,只为更高的技术,更好的明天,O(∩_∩)O哈哈~