今天我遇到一个问题,推测一个方法没有释放锁,导致死锁情况。
环境:
这是tomcat上的一个Web应用程序,当用户从UI调用服务器时,线程进入一个servlet。 servlet有一个自动装配的spring bean,通过servlet中的方法调用bean中的方法。
该方法是同步的,它所做的只是通过spring jdbc模板批量插入(Oracle DB)一个String的列表。(2行代码,1个jdbcTemplate批量更新和一个日志)
在测试我的浏览器时,我将其关闭并且关闭了它,并且没有人能够进入同步方法。
在这种情况下使用synchronized时,在这种情况下是否需要记住一些事项?有没有人猜测可能发生了什么?我怎样才能保证锁定会在一段时间后释放?
谢谢
public class LockManager {
private JdbcTemplate jdbcTemplate;
private static final Log LOG = LogFactory.getLog(LockManager.class);
/* synchronized to guarantee that only one thread at a time is inserting. */
public synchronized void lockTransactions(final List<String> idList, final String userID) throws MyException{
try{
final Timestamp occuranceTime = new Timestamp(System.currentTimeMillis());
jdbcTemplate.batchUpdate(INSERT_ID, new LockInsertBatchPreparedStatementSetter(idList,userID, occuranceTime));
LOG.info("Lock Rows completed. ID List size="+idList.size());
}catch(Exception e){
handleInsertException(e);
}
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/* Throw appropriate exception. */
private void handleInsertException(final Exception e) throws MyException{
String message = e.getMessage();
MyException me = null;
if(message.contains("ORA-00001")){
me= new MyException(ExceptionMessage.LOCK_CONSTRAINT.getMessage(),e);
}else{
me= new MyException(ExceptionMessage.LOCK_ERROR.getMessage(),e);
}
LOG.error("Exception while locking IDs",me);
throw me;
}
private class LockInsertBatchPreparedStatementSetter implements BatchPreparedStatementSetter{
private List<String> idList;
private String userID;
private Timestamp occuranceTime;
private final Log LOG = LogFactory.getLog(LockInsertBatchPreparedStatementSetter.class);
public LockInsertBatchPreparedStatementSetter(final List<String> idList, final String userID, final Timestamp occuranceTime){
this.idList = idList;
this.userID = userID;
this.occuranceTime=occuranceTime;
}
@Override
public int getBatchSize() {
return idList.size();
}
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
String thisID= idList.get(i);
ps.setString(1, thisID);
ps.setString(2, userID);
ps.setTimestamp(3, occuranceTime);
LOG.info("Attempting to Lock ID:"+thisID+ " for user:"+userID);
}
}
}
答案 0 :(得分:3)
首先,您应该确保您的synchronized方法仅包含需要同步的代码。
其次,如果您正在进行像您所提到的DB write这样的操作(批量插入(Oracle DB)),请确保在此类操作上设置超时。如果您的批量插入时间太长,可能由于各种原因而发生。超时应该有助于快速完成工作,或者只是退出而不完成工作。
同步方法中的任何慢速操作肯定会成为尝试输入该方法的其他线程的杀手。