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