java----并发编程
任务定时调度
简单任务调度(Timer类)
public static void main(String[] args) {
Timer timer = new Timer();
//1秒后执行run(),只执行一次
// timer.schedule(new TimerTask() {
// @Override
// public void run() {
// System.out.println("test");
// }
// },1000);
//1秒之后每隔一秒执行run()方法
// timer.schedule(new TimerTask() {
// @Override
// public void run() {
// System.out.println("test");
// }
// },1000,1000);
GregorianCalendar gregorianCalendar = new GregorianCalendar(2019, 9, 1, 19, 20,00);
//Tue Oct 01 19:20:00 CST 2019 注意0是1月
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("test");
}
}, gregorianCalendar.getTime(),1000);
}
复杂的任务调度
quartz框架(已经集成到spring中了)
如果需要系统学习这个框架,需要将这个框架下载下来,里面example中有使用案例;
使用maven下载依赖
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.1</version>
</dependency>
基本使用
实际过程中直接使用,不需要写,example中有使用案例。
public class Demo {
public static void main(String[] args) {
//创建Scheduler工厂
StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
//从工厂获得调度器
try {
Scheduler scheduler = stdSchedulerFactory.getScheduler();
//设置时间规则
Date date = DateBuilder.evenSecondDateAfterNow();
//设置执行的工作
JobDetail jobDetail= JobBuilder.newJob(Test.class).withIdentity("test").build();
//设置触发条件
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger").startAt(date).build();
//注册任务和条件
scheduler.scheduleJob(jobDetail,trigger);
scheduler.start();
//scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
必须是一个public类
public class Test implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("started");
}
}
补充
//每隔2秒执行一次,重复3次(一共会重复4次)
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger").startAt(date).withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).withRepeatCount(3)).build();
HappenBefore
你写的代码很可能根本没按你期望的顺序执行,因为编译器和CPU会尝试重排指令使得代码更快地运行,称为指令重排。
前提是数据之前没有依赖,可能后面的代码会先执行
首先自己写的代码会被编译成机器指令(其中的变量会被决定有那个寄存器存储)
从内存中获取一条指令。从对应的寄存器中获取相应的数据值(copy一份到工作内存),cpu计算结果,同步到主存中(这一步可能会出现问题,原因同步比较慢)
同步数据慢:造成数据不一致
数据之间没有依赖:操作指令重排
public class Demo {
private static int a=0;
private static Boolean flag=false;
public static void main(String[] args) {
//如果没有出错,可以将循环次数加大
for (int i = 0; i < 100; i++) {
a = 0;
flag = false;
Thread t1 = new Thread(() -> {
a = 1;
flag = true;
});
Thread t2 = new Thread(() -> {
if (flag){
a*=1;
}
//按照预期值a是不可能是0的
if (a==0){
System.out.println("happed before-->a="+a);
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
ThreadLocal
即使定义在成员变量中,所有的线程对他的操作相互不影响,都把他当做了局部变量。
public class Demo {
private volatile static int i = 0;
private static ThreadLocal threadLocal1 = new ThreadLocal<Integer>();
private static ThreadLocal threadLocal2 = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 0;
}
};
public static void main(String[] args) throws InterruptedException {
//默认初始化为null;
System.out.println(threadLocal1.get());
//重写initialValue方法,赋给初始值.
System.out.println(threadLocal2.get());
new Thread(()->{
threadLocal1.set(11);
System.out.println(threadLocal1.get());
}).start();
new Thread(()->{
System.out.println(threadLocal1.get());
}).start();
}
}
InheritableThreadLocal
和ThreadLocal用法一样,只是子线程会继承父线程的数据,但是子线程修改数据不会影响父线程,一旦子线程修改了了数据,父线程在修改数据就不会影响子线程了。

浙公网安备 33010602011771号