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用法一样,只是子线程会继承父线程的数据,但是子线程修改数据不会影响父线程,一旦子线程修改了了数据,父线程在修改数据就不会影响子线程了。

 

posted @ 2019-04-20 18:48  小名的同学  阅读(331)  评论(0编辑  收藏  举报