在构造多线程的时候,线程自己也须要托管到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的名字获取对应名字。就能够变成局部变量,使得线程安全了。 多线程