Web项目中简单的多线程使用
**
Java多个线程同时访问操作单例对象,需不需要加锁的问题
** (1)多个线程处理单例对象的共有属性需加锁 ps:多个线程同时访问同一个方法,该方法操作了单例对象中共有(全局)的属性,则需要加锁。 (2)多个线程访问单例对象的同一方法,但该方法不处理共有属性则不需要加锁 (3)多个线程访问单例对象的static属性、方法需要加锁
结论: 操作共有属性,静态方法属性,加锁;只是调用方法,没有操作共有属性,不加锁。 方法中定义的局部变量在多线程下不会带来线程安全的问题。 **
线程的循环、休眠和停止
** public void testCron1() throws Exception { DateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”); log.info(sdf.format(new Date())+"*****每1秒执行一次"); Thread thread = Thread.currentThread(); while (!thread.isInterrupted()) { log.info(sdf.format(new Date())+“线程循环”); long now = (new Date()).getTime(); if((now%3 == 0)){ log.info(now+“线程停止”); thread.interrupt(); }else if ((now%2 == 0)) { log.info(now+“进入休眠状态”); thread.sleep(10000); } } } 注意:进入休眠状态再度循环的是while里的代码 **
Spring注入与多线程
** Spring不能在线程中注入,在线程中使用@Resource或者@Autowired注入全部为NULL 解决: 1、将需要注入的Bean在线程创建前就注入或者作为线程的构造函数参数传入
多线程定时器:
@Autowired private HsSchedulerMapper hsSchedulerMapper; @Autowired @Qualifier("ApplyAccount")private HsSchedule ApplyAccount; private ConfigResources cfg = new ConfigResources(HsjkClient.class.getResourceAsStream("/HS.properties")); private HttpClient client = new HttpClient(); //线程1 @Scheduled(cron="0/5 * * * * ? ") //每4秒执行一次 public void testCron6() { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.info(sdf.format(new Date())+"*********线程1执行一次"); ApplyAccount.scheduleTaskFirst(cfg, client, hsSchedulerMapper); } //线程2 @Scheduled(cron="0/5 * * * * ? ") //每4秒执行一次 public void testCron7() { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.info(sdf.format(new Date())+"*********线程2执行一次"); ApplyAccount.scheduleTaskSecond(cfg, client, hsSchedulerMapper); }
作为构造函数参数传入:
class Test{ //这两个为线程所需要的Bean @Resource TestDao1 testDao1; @Resource TestDao2 testDao2; public void serviceExecute(){ //在这里开启线程,执行操作 ThreadExample te = new ThreadExample(TestDao1 testDao1,TestDao2 testDao2); te.start(); } //内部类 private class ThreadExample extends Thread{ private TestDao1 testDao1 = null; private TestDao2 testDao2 = null; public ThreadExample(TestDao1 testDao1,TestDao2 testDao2){ //也可以在构造函数中传入参数 this.testDao1 = testDao1; this.testDao2 = testDao2; } public void run(){ //这里为线程的操作 //就可以使用注入之后Bean了 testDao1.xxx(); testDao2.xxx(); } } }
2、使用ApplicationContext.getBean方法来静态的获取Bean (摘抄自https://www.cnblogs.com/vinozly/p/5223147.html) (1)定义工具类
@Component public class SpringApplicationContextHolder implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext context) throws BeansException { SpringApplicationContextHolder.context = context; } public static Object getSpringBean(String beanName) { notEmpty(beanName, "bean name is required"); return context==null?null:context.getBean(beanName); } public static String[] getBeanDefinitionNames() { return context.getBeanDefinitionNames(); }
(2)线程中获取bean
UserRepo user = (UserRepo) SpringApplicationContextHolder.getSpringBean("userRepo");