Java多线程学习笔记2——ThreadLocal

      static在所属环境中,所有线程共享同一份数据,无论哪个线程调用,结构都是一致的。如果是一个普通的的变量会怎样?

案例一、线程内的运行的结果不一致

public class NewThreadOne {
	private int num = 0; //随机数
  
	public static void main(String[] args) {
		NewThreadOne newThreadOne = new NewThreadOne();
		for (int i = 0; i < 2; i++) { //两个线程产生数据,并且调用A,B的获取数据的方法
			new Thread(new Runnable() {
				@Override
				public void run() {
					int num = (int) (Math.random() * 10000);
					System.out.println(Thread.currentThread() + "add num is=" + num);
					newThreadOne.setNum(num);
					A a = newThreadOne.new A();
					a.getData();
					B b = newThreadOne.new B();
					b.getData();
				}
			}).start();
		}
	}
        //两个对象都可以获取数据
	class A {
		public void getData() {
			System.out.println("the class A ," + Thread.currentThread() + ",getData is=" + getNum());
		}
	}
	class B {
		public void getData() {
			System.out.println("the class B ," + Thread.currentThread() + ",getData is=" + getNum());
		}
	}
	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}
}

获取数据的经过如下:
Thread[Thread-0,5,main]add num is=4253
Thread[Thread-1,5,main]add num is=2030
the class A ,Thread[Thread-0,5,main],getData is=2030
the class A ,Thread[Thread-1,5,main],getData is=2030
the class B ,Thread[Thread-1,5,main],getData is=2030
the class B ,Thread[Thread-0,5,main],getData is=2030

结果可见,线程内的数据数据没有共享。怎么让各现场的数据都是独立的呢?

public class NewThreadOne {
	private int num = 0;
	Map<Thread, Integer> map=new HashMap<>();
	public static void main(String[] args) {
		NewThreadOne newThreadOne = new NewThreadOne();
		for(int i=0;i<2;i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					int num = (int) (Math.random() * 10000);
					newThreadOne.map.put(Thread.currentThread(), num);
					System.out.println(Thread.currentThread()+"add num is="+num);
					newThreadOne.setNum(num);
					A  a=newThreadOne.new A();
					a.getData();
					B  b=newThreadOne.new B();
					b.getData();
				}
			}).start();
		}
	}
	class A {
		public void getData() {
			System.out.println("the class A ," + Thread.currentThread() + ",getData is=" + map.get(Thread.currentThread()));
		}
	}
	class B {

		public void getData() {
			System.out.println("the class B ," + Thread.currentThread() + ",getData is=" + map.get(Thread.currentThread()));
		}
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}	
}

各自的结果从当前线程中拿到数据,实现线程内的数据共享。案例:在数据库中例如银行实现转账,线程内转入,转出在同一个线程共享区域。最终结果和线程外共享。

2、使用threadlocal实现

threadlocal提供了set(T t) 和get()方法,set的结果和当前的线程绑定,set代码如下:

 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

get也是从当前线程中取出,和上面的事例原理想象,如果案例中代码使用threadlocal会很方便代码如下:

package com.thread;

public class NewThreadOne {
	private int num = 0;
	ThreadLocal<Integer>  local=new ThreadLocal<>();
	public static void main(String[] args) {
		NewThreadOne newThreadOne = new NewThreadOne();
		for (int i = 0; i < 2; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					int num = (int) (Math.random() * 10000);

					newThreadOne.local.set(num);

					System.out.println(Thread.currentThread() + "add num is=" + num);
					newThreadOne.setNum(num);
					A a = newThreadOne.new A();
					a.getData();
					B b = newThreadOne.new B();
					b.getData();
				}
			}).start();
		}
	}
	class A {
		public void getData() {
			System.out.println(
					"the class A ," + Thread.currentThread() + ",getData is=" + local.get());
		}
	}
	class B {

		public void getData() {
			System.out.println(
					"the class B ," + Thread.currentThread() + ",getData is=" + local.get());
		}
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}

}

经测试结果一致。

进一步升级:如下的代码把threadlocal封装到线程共享业务里面更合理。

public class NewThreadOne {
	private int num = 0;
	public static void main(String[] args) {
		//
		NewThreadOne newThreadOne = new NewThreadOne();
		//
		for (int i = 0; i < 2; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					int num = (int) (Math.random() * 10000);
					
					Person p = Person.getInstance();
					p.setName("zkk" + num);
					p.setAge(num);
					//
					System.out.println(Thread.currentThread() + "add num is=" + num);
					newThreadOne.setNum(num);
					//
					A a = newThreadOne.new A();
					a.getData();
					//
					B b = newThreadOne.new B();
					b.getData();
				}
			}).start();
		}
	}

	class A {
		public void getData() {
			System.out.println("the class A ," + Thread.currentThread() + ",getData is=" + Person.local.get().getName());
		}
	}

	class B {

		public void getData() {
			System.out.println("the class B ," + Thread.currentThread() + ",getData is=" + Person.local.get().getName());
		}
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

}

class Person {
	
	static ThreadLocal<Person> local = new ThreadLocal<>();

	private Person() {};

	private static Person person = null;
	//
	public synchronized static Person getInstance() {
		//
		if (local.get() == null) {
			person = new Person();
			local.set(person);
		}
		return local.get();
	}
	//
	private String name;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}



猜你喜欢

转载自blog.csdn.net/zhangkang65/article/details/79295850
今日推荐