目的
保護一組資源中的每個資源都不會受到併發訪問而導致不一致
例子代碼
男: 砸了你的攤, 逼着你離開, 最後知道真相的我眼淚掉下來, 砸了你的攤, 我背了良心債, 就算付出再多感情也再買不回來
女: 當初是你要分開, 分開就分開, 如今又要用真(政)愛(策), 把我哄回來, 擺攤不是你想擺, 想擺就能擺, 讓我掙開, 讓我明白, 放手你的愛
擺攤經濟一出, 各國人都開啓了擺攤之旅:
可是攤位有限, 不能隨便擺哦, 我們來講講這裏面的故事:
我們定義一下貨物類:
//商品
@Data
@AllArgsConstructor
public class Goods {
private String name;
}
定義一個攤位類:
//攤位
@Data
@AllArgsConstructor
public class Stall {
private Integer number;
private String name;
private List<Goods> saleGoods;
}
定義一個擺攤的人:
//擺攤人
@Data
@AllArgsConstructor
public class People {
private String name;
private List<Goods> saleGoods;
}
我們三個人同時去擺攤:
List<People> peopleList = new ArrayList<>();
peopleList.add(new People("小李", Arrays.asList(new Goods("小李皮鞋"), new Goods("小李運動鞋"))));
peopleList.add(new People("小王", Arrays.asList(new Goods("小王西瓜"), new Goods("小王椰子"))));
peopleList.add(new People("小張", Arrays.asList(new Goods("小張肥皂"), new Goods("小張洗衣液"))));
List<Stall> stallList = new ArrayList<>();
stallList.add(new Stall(1,"攤位一",new ArrayList<>()));
stallList.add(new Stall(2,"攤位二",new ArrayList<>()));
peopleList.parallelStream().forEach(
(people) -> {
for (Stall stall : stallList) {
if(stall.getSaleGoods().isEmpty()) {
stall.setName(people.getName() + "的攤位");
//拜訪貨物中
putGoods2Stall();
stall.setSaleGoods(people.getSaleGoods());
}
}
}
);
System.out.println(stallList.toString());
輸出:
[Stall(number=1, name=小李的攤位, saleGoods=[Goods(name=小李皮鞋), Goods(name=小李運動鞋)]), Stall(number=2, name=小王的攤位, saleGoods=[Goods(name=小張肥皂), Goods(name=小張洗衣液)])]
問題分析
這個和互斥模式是一樣的, 主要是狀態的不一致, 小王賣了小張的貨, 如果用互斥模式來解決也沒什麼問題, 就是如果對stallList 加鎖粒度太大, 併發不高, 如果是對單個攤位加鎖, 要注意加鎖順序, 代碼也會複雜一些.
信號量模式
List<People> peopleList = new ArrayList<>();
peopleList.add(new People("小李", Arrays.asList(new Goods("小李皮鞋"), new Goods("小李運動鞋"))));
peopleList.add(new People("小王", Arrays.asList(new Goods("小王西瓜"), new Goods("小王椰子"))));
peopleList.add(new People("小張", Arrays.asList(new Goods("小張肥皂"), new Goods("小張洗衣液"))));
Semaphore semaphore = new Semaphore(2);
peopleList.parallelStream().forEach(
(people) -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(people.getName() + "開始擺攤");
Stall stall = new Stall();
stall.setName(people.getName() + "的攤位");
//擺放貨物中
putGoods2Stall();
stall.setSaleGoods(people.getSaleGoods());
System.out.println(LocalDateTime.now() + "" + stall.toString());
semaphore.release();
}
);
輸出:
小王開始擺攤
小李開始擺攤
2020-06-06T13:04:03.710Stall(number=null, name=小王的攤位, saleGoods=[Goods(name=小王西瓜), Goods(name=小王椰子)])
2020-06-06T13:04:03.710Stall(number=null, name=小李的攤位, saleGoods=[Goods(name=小李皮鞋), Goods(name=小李運動鞋)])
小張開始擺攤
2020-06-06T13:04:05.713Stall(number=null, name=小張的攤位, saleGoods=[Goods(name=小張肥皂), Goods(name=小張洗衣液)])