在構造多線程的時候,線程自己也須要託管到spring上去運行,因爲須要注入一些變量致使原來使用單例的變量使用的是成員變量,使得注入值的時候發生了「競態」致使了線程不安全。例如原來寫的代碼: java
@Service("winningCodeService") public class WinningCodeServiceImpl implements WinningCodeService { private static Log log = LogFactory.getLog(WinningCodeServiceImpl.class); private static BlockingQueue<WinningCode> winningCodeQueue = new LinkedBlockingQueue<WinningCode>(); private static BlockingQueue<ChargeResponse> sendToPhpQueue = new LinkedBlockingQueue<ChargeResponse>(); private String dir;//winningCodeQueue鎖處在的目錄 private String encode;//編碼格式 private String toPhpUrl;//到PHP的地址 @Autowired private SendToDDTApi sendToDDTApi; @Autowired private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Autowired private SendFinalResultToPhp sendFinalResultToPhp; @Autowired private ChargeRecodeDao chargeRecodeDao; @Autowired private WinningCodeDao winningCodeDao; @Override public void putToDDTApi(WinningCode winningCode) { log.info(winningCode); winningCodeQueue.offer(winningCode); log.debug("插入前的數量:"+winningCodeQueue.size()); } @Override public void beginSendToDDT(final String url) { threadPoolTaskExecutor.execute(new Runnable() { @Override public void run() { taskSendToDDT(url); } }); } private void taskSendToDDT(String url) { while (true) { WinningCode winningCode = null; try { log.debug("獲取時候的數量:"+winningCodeQueue.size()); winningCode = winningCodeQueue.take(); } catch (InterruptedException e) { e.printStackTrace(); } sendToDDTApi.setWinningCode(winningCode);//在該狀態下會發生競態致使程序出錯。 sendToDDTApi.setUrl(url); threadPoolTaskExecutor.execute(sendToDDTApi); } } }
@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class SendToDDTApi implements Runnable { private static Log log = LogFactory.getLog(SendToDDTApi.class); private String url; @Autowired private PrizeCodeLibraryDao prizeCodeLibraryDao; @Autowired private WinningCodeDao winningCodeDao; @Autowired private WinningCodeService winningCodeService; @Autowired private ResendService resendService; private WinningCode winningCode; private String appKey; private String appSecret; @Override public void run() { try { pushToDDT(); } catch (InterruptedException e) { e.printStackTrace(); } } private void pushToDDT() throws InterruptedException { String serialNumber = winningCode.getSerialNumber(); String md5 = MD5.getMD5Code(winningCode.getPrizedCode()); PrizeCodeLibrary prizeCode = prizeCodeLibraryDao.findByPrizeCode(md5); if(prizeCode==null){ throw new PrizeException("獎碼查詢爲空"); } winningCode.setAmount(prizeCode.getAmount()); winningCode.setRank(prizeCode.getRank()); winningCode.setExpiryTime(new Date()); WinningCode win = winningCodeDao.findWinningCodeBySerialNumber(serialNumber); if(win==null){ winningCodeDao.insertWinningCode(winningCode); } String result = null; try{ result = SendRequest(winningCode); }catch (Exception e) { winningCodeService.saveChargeRecode(winningCode.getSerialNumber(),null); winningCodeDao.updateChargeStatBySerialNumber(winningCode.getSerialNumber(), ChargeStatus.CHARGE_FAILURE.getCode()); resendService.resendOrSendFailure(serialNumber); log.error(e); } log.info("返回的值:" + result); if(result!=null){ checkResult(result, winningCode); } } }
如今在服務代碼中加入如下, spring
@Autowired private BeanFactory beanFactory;
而且將線程代碼添加如下代碼讓該線程變爲多實例 安全
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
而且在服務代碼中,根據bean的名字獲取對應名字。就能夠變成局部變量,使得線程安全了。 多線程