我有以下代码:
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类中的调用方法:
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值。但是我希望它是101,因为 m_nLegId ++; 语句。 似乎第二个线程在第一个线程执行的同步块结束之前设法进入代码。
我该如何解决?
谢谢
答案 0 :(得分:2)
对我而言,您的错误与m_nLegId
是static field
并且您尝试同步当前实例而不是类的访问权限有关,因此您不能正确防止并发修改你的领域。
我的意思是
synchronized (this) {
应该是
synchronized (LegJoinSp.class) {
注意:如果您只需要一个计数器,请考虑为您的字段使用AtomicInteger
而不是int。
答案 1 :(得分:1)
问题是您正在为每个线程创建一个新对象,但是您应用锁定的方式仅适用于同一个对象(因为您在此上应用了锁定)。
因此,如果你想在类级别上应用锁定,那么你可以创建一个静态对象并对该对象应用锁定,这可以达到你想要达到的目的(如果我根据评论)