多线程高级编程(1)

1, 任务定时调度

Timer 和 TimerTask

package y.i.d;

import java.sql.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Timer;
import java.util.TimerTask;

/** 
 * timer 是用来跑定时任务的 
 * 
 * */


public class TestTimer {
	public static void main(String[]  args){
		Timer timer = new Timer();
		// timer.schedule(new MyTask(), 2000); // 2秒延时后跑
		// timer.schedule(new MyTask(), 5000,2000); // 5秒开始执行, 每两秒重复一次
		Date calendar = new Date(3000);
		 timer.schedule(new MyTask(), calendar,2000); // 中间的开始参数也可以是Calendar类
		
	}
}
class MyTask extends TimerTask{
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println("ssssss");
		}
	 System.out.println("-----end---------");
		
	}
}

2,如果遇到复杂的时间任务调度,那么就需要借助quartz 石英钟 定时任务框架来解决了 ,已经集成到了spring框架里;

DSL 编码风格:是指 简直连贯的编码风格解决特定问题的, 比如 lamda表达式 ,链式调用,嵌套函数。

quartz  运用的就是链式调用的模式

3,happenBefore 指令重排,目的是硬件为了提高性能

你写的代码没有按照预期顺序排列,编译中 编译器和cpu 会尝试按照最简单的方式去处理,所以就会出现这种打乱的情况;

一条指令的四个执行步骤: 一:从内存中读取指令 。二:cpu 对指令进行解码。 三,从寄存器中拿到数据,并进行计算,四,放回到寄存器中。

一般指令重排发生在 计算 中还没有放回到寄存器中, 如果判断在线程中这条指令不耦合,cpu就没有等直接对下一条指令进行解码执行。单线程没有问题,对我们多线程就会造成影响,可能会并发。

指令重排会发生在硬件层面和虚拟机层面;

package y.i.d;
/**
 * mac电脑线无法重现指令重排 ,可能底层不一样
 * 
 * 
 * */
public class HappenBefore {
	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;
				System.out.println("ing-->"+a);
			}
			
			if(a==0) {// a==0 
				System.out.println("happenBefore-->"+a);// a==1 值还没回来,就已经打印了
			}
			});
			
			
			t1.start();
			t2.start();
			try {
				t1.join();
				t2.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		
		
	}
}

4, volatile 保证 线程间 数据的 可见性, 简单的说就是 直接操作主内存,没有经过缓存,对于各个线程间都是可见的,但是不保证原子性(读改写不是一个步骤完成的,可能读了因为引用数据被前一个指令更新又要重新读取然后再改和写,这样就是两个步骤,1,读,2,读改写),CAS保证原子性,

volatile 是syncronized的轻量实现, 保证了数据的同步 ,没有保证并发的安全性;

volatile 可以避免指令重排造成数据不同步的影响;

package y.i.d;



public class VolatileTest {
	private volatile static int num = 0; // volatile使得内存数据和线程中的同步
	public static void main(String[]  args){
			Thread thread = new Thread(()->{
				while(num==0) { // volatile能更新到1
				}
			
			});
			 
			thread.start();
			try {
				thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			num =1;
			System.out.println("");
		
	}
}
发布了189 篇原创文章 · 获赞 10 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wangrong111222/article/details/102639705
今日推荐