Java: 线程同步失败
Java: Fail in synchronizing threads
我有以下代码:
for (int iThreadCounter = 1; iThreadCounter <= CONNECTIONS_NUM; iThreadCounter++){
WorkThread wt = new WorkThread(iThreadCounter);
new Thread(wt).start();
m_arrWorkThreadsToCreate.add(wt);
}
那些线程调用以下代码:
int res = m_spLegJoin.call(m_workTread, m_workTread.getConfId());
这是LegJoinSp里面的调用方法class:
public class LegJoinSp extends ConnEventSp {
private static final int _LEG_JOIN_ACTION_CODE = 22;
private static int m_nLegId = Integer.valueOf(IniUtils.getIniValue("General", "LEG_ID_START"));
private final Lock m_lock = new ReentrantLock();
public int call(WorkThread a_workThread, String a_sConfId) {
synchronized (this) {
//m_lock.lock();
m_nLegId++;
boolean bPass = false;
Log4jWrapper.writeLog(LogLevelEnum.DEBUG, "LegJoinSp - call", "a_workThread = " + a_workThread.getThreadId() + " a_sConfId = " + a_sConfId);
if (super.call(a_workThread, a_sConfId, _LEG_JOIN_ACTION_CODE, "" + m_nLegId) == 0) {
bPass = true;
} else {
bPass = false;
}
//m_lock.unlock();
if (bPass) {
Log4jWrapper.writeLog(LogLevelEnum.DEBUG, "LegJoinSp - call", "a_workThread = " + a_workThread.getThreadId() + " a_sConfId = " + a_sConfId + " returned leg id " + m_nLegId);
return m_nLegId;
} else {
return -1;
}
}
}
public Lock getLock() {
return m_lock;
}
}
我有 2 个线程调用此 call() 方法。
m_nLegId 以 100 开头。
如您所见,我尝试用
锁定方法
synchronized(this)
和
m_lock.lock() and m_lock.unlock()
问题是,当我第一次访问 if (bPass) 内部代码时,它将 102 作为 m_nLegId 值写入我的日志。但是,由于 m_nLegId++; 语句,我希望它是 101。
似乎第二个线程设法在第一个线程执行的同步块结束之前进入代码。
我该如何解决?
谢谢
问题是您正在为每个线程创建一个新对象,但是您应用锁的方式仅适用于同一对象(因为您在 this 上应用了锁).
所以如果你想在 class 级别上应用锁,那么你可以创建一个静态对象并在该对象上应用锁,这可以达到你想要实现的目的(如果我理解你的根据评论正确解决问题)
对我来说,你的错误与 m_nLegId
是一个 static field
这一事实有关,你试图同步对当前实例的访问而不是 class 这样你就不会无法正确阻止您的字段的并发修改。
我是说
synchronized (this) {
应该是
synchronized (LegJoinSp.class) {
注意: 如果您只需要一个计数器,请考虑为您的字段使用 AtomicInteger
而不是 int。
我有以下代码:
for (int iThreadCounter = 1; iThreadCounter <= CONNECTIONS_NUM; iThreadCounter++){
WorkThread wt = new WorkThread(iThreadCounter);
new Thread(wt).start();
m_arrWorkThreadsToCreate.add(wt);
}
那些线程调用以下代码:
int res = m_spLegJoin.call(m_workTread, m_workTread.getConfId());
这是LegJoinSp里面的调用方法class:
public class LegJoinSp extends ConnEventSp {
private static final int _LEG_JOIN_ACTION_CODE = 22;
private static int m_nLegId = Integer.valueOf(IniUtils.getIniValue("General", "LEG_ID_START"));
private final Lock m_lock = new ReentrantLock();
public int call(WorkThread a_workThread, String a_sConfId) {
synchronized (this) {
//m_lock.lock();
m_nLegId++;
boolean bPass = false;
Log4jWrapper.writeLog(LogLevelEnum.DEBUG, "LegJoinSp - call", "a_workThread = " + a_workThread.getThreadId() + " a_sConfId = " + a_sConfId);
if (super.call(a_workThread, a_sConfId, _LEG_JOIN_ACTION_CODE, "" + m_nLegId) == 0) {
bPass = true;
} else {
bPass = false;
}
//m_lock.unlock();
if (bPass) {
Log4jWrapper.writeLog(LogLevelEnum.DEBUG, "LegJoinSp - call", "a_workThread = " + a_workThread.getThreadId() + " a_sConfId = " + a_sConfId + " returned leg id " + m_nLegId);
return m_nLegId;
} else {
return -1;
}
}
}
public Lock getLock() {
return m_lock;
}
}
我有 2 个线程调用此 call() 方法。 m_nLegId 以 100 开头。 如您所见,我尝试用
锁定方法synchronized(this)
和
m_lock.lock() and m_lock.unlock()
问题是,当我第一次访问 if (bPass) 内部代码时,它将 102 作为 m_nLegId 值写入我的日志。但是,由于 m_nLegId++; 语句,我希望它是 101。 似乎第二个线程设法在第一个线程执行的同步块结束之前进入代码。
我该如何解决?
谢谢
问题是您正在为每个线程创建一个新对象,但是您应用锁的方式仅适用于同一对象(因为您在 this 上应用了锁).
所以如果你想在 class 级别上应用锁,那么你可以创建一个静态对象并在该对象上应用锁,这可以达到你想要实现的目的(如果我理解你的根据评论正确解决问题)
对我来说,你的错误与 m_nLegId
是一个 static field
这一事实有关,你试图同步对当前实例的访问而不是 class 这样你就不会无法正确阻止您的字段的并发修改。
我是说
synchronized (this) {
应该是
synchronized (LegJoinSp.class) {
注意: 如果您只需要一个计数器,请考虑为您的字段使用 AtomicInteger
而不是 int。