在开发游戏的野外BOSS战时,使用synchronized(Object o)锁定方法块,一时没注意,发生了并发数据异常。
package com.test;
import java.util.HashMap;
import java.util.Map;
public class TestRunnable implements Runnable{
int num = 0;
public TestRunnable(int num){
this.num = num;
}
@Override
public void run() {
TestAction action = new TestAction();
//参数:用户名
action.action("user_"+num);
}
public static void main(String[] args) {
for(int i=1;i<=10;i++){
//10个线程,每个线程获取不同的User
Thread t = new Thread(new TestRunnable(i));
t.setName("thread"+i);
t.start();
}
}
}
class TestAction {
//全局唯一场景对象
private static TestScene scene = new TestScene();
public void action(String userName){
TestUser user = scene.getUser(userName);
//锁定对象是user,不同用户多线程并发调用时,场景唯一对象scene中的属性count数据异常
synchronized (user) {
scene.setCount(scene.getCount()+1);
}
}
}
class TestScene {
int count = 0;
private Map<String,TestUser> map = new HashMap<String,TestUser>() ;
public TestScene(){
init();
}
//初始化10个用户到场景中
public void init(){
for(int i=1;i<=10;i++){
TestUser entity = new TestUser();
entity.setName("user_"+i);
map.put(entity.getName(), entity);
}
}
public int getCount() {
return count;
}
public void setCount(int count) {
System.out.println(Thread.currentThread().getName()+" old:"+this.count+" new:"+count);
this.count = count;
}
public TestUser getUser(String name) {
return map.get(name);
}
}
class TestUser {
Object lock = new Object();
String name;
public Object getLock() {
return lock;
}
public void setLock(Object lock) {
this.lock = lock;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
synchronized (Object o):在对象o上打开锁,方法块中的代码,应该只修改o的属性。如果需要修改其他对象的数据,需要根据实际情况,另外加锁。