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");
