• 在一个类中使用了 static 成员变量的时候,一定要多问问自己,这个 static 成员变量需要考虑“线程安全”吗?
  • (也就是说,多个线程需要独享自己的 static 成员变量吗?)如果需要考虑,那就请用 ThreadLocal !
  • 当多个线程同时读写同一共享变量时存在并发问题,如果不共享不就没有并发问题了,一个线程存一个自己的变量
  • 类比原来好几个人玩同一个球,现在一个人一个球,就没有问题了

Map/Set

  • 在Java 的 设计中,Set 就是 只有Key 没有Value 的 map

ThreadLocal 是用来多线程共享数据的

  1. 就是一个Map。key - 》 Thread.getCurrentThread(). value - 》 线程需要保存的变量。
  2. ThreadLocal.set(value) -> map.put(Thread.getCurrentThread(), value);
  3. ThreadLocal.get() -> map.get(Thread.getCurrentThread());
  4. 内存问题 : 在并发量高的时候,可能有内存溢出。
  5. 使用ThreadLocal的时候,一定注意回收资源问题,
  6. 每个线程结束之前,将当前线程保存的线程变量一定要删除_ ThreadLocal.remove();


	volatile static String name = "zhangsan";
	static ThreadLocal<String> tl = new ThreadLocal<>();

	public static void main(String[] args) {
		tl.set("lusifer");
		System.out.println(Thread.currentThread().getName()+"-- tl.get >"+tl.get());
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+"-- tl.get >"+tl.get());
					TimeUnit.SECONDS.sleep(2);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"-- t1 >  name "+name);
				System.out.println(Thread.currentThread().getName()+"-- tl.get >"+tl.get());
			}
		}).start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+"-- t2 >  name "+name);
					System.out.println(Thread.currentThread().getName()+"-- tl.get >"+tl.get());
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				name = "lisi";
				tl.set("wangwu");
				System.out.println(Thread.currentThread().getName()+"-- t2>  name "+name);
			}
		}).start();
		System.out.println(Thread.currentThread().getName()+"--main >  name "+name);
		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"-- tl.geteeeee >"+tl.get());
		
		System.out.println(Thread.currentThread().getName()+"--main >两秒后的  name "+name);
	}




/**

*/
public class UserInfo {

	public static ThreadLocal<String> info = new ThreadLocal<String>();

	public static String getInfo() {
		return info.get();
	}

	public static void setInfo(String value) {
		info.set(value);
	}
}


不安全的


public class NumUtil {

//	public static int addNum = 0;
	static ThreadLocal<Integer> addNum = ThreadLocal.withInitial(() -> 0);

	public static int add10(int num) {
//		addNum = num;
		addNum.set(num);
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
//		return addNum +10;
		return addNum.get() + 10;
	}

	public static void main(String[] args) {

		ExecutorService service = Executors.newFixedThreadPool(20);

		for (int i = 0; i < 20; i++) {
			int num = i;
			service.execute(() -> {
				System.out.println(num + " " + NumUtil.add10(num));
			});
		}
		service.shutdown();
	}
}




public class DateUtil {

	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public static Date parse(String dateStr) {
		Date date = null;
		try {
			date = sdf.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}

	public static void main(String[] args) {

		ExecutorService service = Executors.newFixedThreadPool(200);

		for (int i = 0; i < 200; i++) {
			service.execute(() -> {
				System.out.println(DateUtil.parse("2019-06-01 16:34:30"));
			});
		}
		service.shutdown();
	}
}