1 回答
ibeautiful
TA貢獻1993條經(jīng)驗 獲得超6個贊
解決問題的第一步就是要確保你保護的是數(shù)據(jù),而不是代碼,先將同步從方法聲明移到方法體里。在上面這個簡短的例子中,剛開始好像能修改的地方并不多。不過我們考慮的是整個GameServer類,而不只限于這個join()方法:
class GameServer {public Map> tables = new HashMap>();public void join(Player player, Table table) {
synchronized (tables) {if (player.getAccountBalance() > table.getLimit()) {
List tablePlayers = tables.get(table.getId()); if (tablePlayers.size() < 9) {
tablePlayers.add(player);
}
}
}
}public void leave(Player player, Table table) {/* body skipped for brevity */}public void createTable() {/* body skipped for brevity */}public void destroyTable(Table table) {/* body skipped for brevity */}
}1234567891011121314151617
這看似一個很小的改動,卻會影響到整個類的行為。當(dāng)玩家加入牌桌 時,前面那個同步的方法會鎖在GameServer的this實例上,并與同時想離開牌桌(leave)的玩家產(chǎn)生競爭行為。而將鎖從方法簽名移到方法內(nèi)部以后,則將上鎖的時機往后推遲了,一定程度上減小了競爭的可能性
縮小鎖的作用域
public class GameServer {public Map> tables = new HashMap>();public void join(Player player, Table table) {if (player.getAccountBalance() > table.getLimit()) {
synchronized (tables) {
List tablePlayers = tables.get(table.getId()); if (tablePlayers.size() < 9) {
tablePlayers.add(player);
}
}
}
}//other methods skipped for brevity}123456789101112131415
現(xiàn)在檢查玩家余額的這個耗時操作就在鎖作用域外邊了。注意到了吧,鎖的引入其實只是為了保護玩家數(shù)量不超過桌子的容量而已,檢查帳戶余額這個事情并不在要保護的范圍之內(nèi)。
分拆鎖
public class GameServer {public Map> tables = new HashMap>();public void join(Player player, Table table) {if (player.getAccountBalance() > table.getLimit()) {
List tablePlayers = tables.get(table.getId());
synchronized (tablePlayers) { if (tablePlayers.size() < 9) {
tablePlayers.add(player);
}
}
}
}//other methods skipped for brevity}123456789101112131415
現(xiàn)在我們把對所有桌子同步的操作變成了只對同一張桌子進行同步,因此出現(xiàn)鎖競爭的概率就大大減小了。如果說桌子中有100張桌子的話,那么現(xiàn)在出現(xiàn)競爭的概率就小了100倍。
class GameServer {public Map
synchronized (tables) {if (player.getAccountBalance() > table.getLimit()) {
List
tablePlayers.add(player);
}
}
}
}public void leave(Player player, Table table) {/* body skipped for brevity */}public void createTable() {/* body skipped for brevity */}public void destroyTable(Table table) {/* body skipped for brevity */}
}1234567891011121314151617
這看似一個很小的改動,卻會影響到整個類的行為。當(dāng)玩家加入牌桌 時,前面那個同步的方法會鎖在GameServer的this實例上,并與同時想離開牌桌(leave)的玩家產(chǎn)生競爭行為。而將鎖從方法簽名移到方法內(nèi)部以后,則將上鎖的時機往后推遲了,一定程度上減小了競爭的可能性
縮小鎖的作用域
public class GameServer {public Map
synchronized (tables) {
List
tablePlayers.add(player);
}
}
}
}//other methods skipped for brevity}123456789101112131415
現(xiàn)在檢查玩家余額的這個耗時操作就在鎖作用域外邊了。注意到了吧,鎖的引入其實只是為了保護玩家數(shù)量不超過桌子的容量而已,檢查帳戶余額這個事情并不在要保護的范圍之內(nèi)。
分拆鎖
public class GameServer {public Map
List
synchronized (tablePlayers) { if (tablePlayers.size() < 9) {
tablePlayers.add(player);
}
}
}
}//other methods skipped for brevity}123456789101112131415
現(xiàn)在我們把對所有桌子同步的操作變成了只對同一張桌子進行同步,因此出現(xiàn)鎖競爭的概率就大大減小了。如果說桌子中有100張桌子的話,那么現(xiàn)在出現(xiàn)競爭的概率就小了100倍。
添加回答
舉報
0/150
提交
取消
