隨着用戶的增加,並發現象出現的頻率越來越多 ,這時候如果沒有做好併發處理 ,會造成數據的不一致,然後就需要增加一下鎖,需要不同的用戶 在 同一時間 僅能對一個 對象進行操作,爲了 更好的拓展性,自己寫了個類,用於來管理 併發請求,具體得邏輯 就是 每一個請求過來 獲取唯一鍵值的對象,保證對於同一鍵值處理的請求獲取到的是同一個對象,然後在對同一個對象其進行相關操作時,僅能一條一條處理,用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哈哈~