Thread wide shared variables are implemented using ThreadLocal API

Posted by bills50000 on Wed, 26 Jan 2022 12:41:07 +0100

1. Review

In the previous section, we talked about the shared variables within the thread sharing range. We used a Map(K,V), where key is the thread object being executed, and value stores the variables of thread operation, such as an int type data. We use key to distinguish the variables operated by which object. In this section, we will use ThreadLocal, a dedicated API for sharing variables within a thread.

2. Implement with ThreadLocal

2.1 use ThreadLocal to realize the sharing of basic data types within threads

Use ThreadLocal to implement thread wide shared variables. The code is as follows:

public class ThreadShareData { 
private static ThreadLocal<Integer> threadIntData = new ThreadLocal<Integer>();
public static void main(String[] args) {
	for(int i=0;i<2;i++){
		new Thread(new Runnable(){
			public void run() {
				int data =  (int) (Math.random()*100);
				System.out.println(Thread.currentThread().getName() + " has modify data :" + data);
				threadIntData.set(data);
				new DataReadA().get();
				new DataReadB().get();
			}
		}).start();
	}
}

static class DataReadA{
	public void get(){
		int data = threadIntData.get();
		System.out.println("DataReadA " + Thread.currentThread().getName() 
				+ " get data :" + data);
	}
}

 
static class DataReadB{
	public void get(){
		int data = threadIntData.get();		
		System.out.println("DataReadB  " + Thread.currentThread().getName() 
				+ " get data :" + data);
	}		
}

}

In the code, we declare the shared variable ThreadLocal threadIntData, which will be used in the thread to save the data to be used. Here is a random integer data.

Call threadIntData in the run method of the thread set(data); Back up the data used in the current thread to threadIntData. Since there are two threads here, two data copies will be saved in threadIntData. They are independent within the thread and do not interfere with each other. Since the variables within the thread range are independent, the data read by DataReadA and DataReadB modules is the data operated in the thread they are running. For example, the data read by thread 1 is the data value it set in the run method at that time. Similarly, thread 2 reads its own data value. Finally, we post the operation log:

Thread-1 has modify data :59
Thread-0 has modify data :28
DataReadA Thread-0 get data :28
DataReadA Thread-1 get data :59
DataReadB Thread-0 get data :28
DataReadB Thread-1 get data :59

We observed the above logs and found that the two threads did read their own data.

2.2 use ThreadLocal to realize the sharing of multiple data within threads

As we know in 2.1, ThreadLoca is used to realize the independent access of int data within the thread. Now, if there are multiple pieces of data, such as the name and age of the staff, how to use ThreadLoca to realize the shared variables within the thread, and the two threads access their own student information.

Step 1

Create a Developer class (representing the Developer), which has two member variables: name and age.

static class Developer{
	String name;
	int age;	
	public String getName() {
		String name = threadDeveloper.get().name;
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		int age = threadDeveloper.get().age;
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}

Step 2

Define a ThreadLocal variable inside the Developer class to store thread independent Developer objects

Step 3

Define a static function to get an instance and store it in ThreadLocal inside the Developer class

static ThreadLocal<Developer> threadLocalDeveloper = new ThreadLocal<Developer>();

	private Developer(){}
	static public Developer getThreadInstance(){
		Developer developerInstance = threadLocalDeveloper.get();
		
		if(developerInstance == null){
			developerInstance = new Developer();
			threadLocalDeveloper.set(developerInstance);
		}
		return developerInstance;
	}

In the above getThreadInstance function, first call threaddeveloper Get () gets the copy of the Developer object owned by the thread. If it is null, a new Developer object is created and stored in ThreadLocal Developer. The ThreadLocal Developer here stores Developer instances related to the currently running threads, so the two threads now store an independent Developer copy for each by sharing ThreadLocal Developer.

Finally, as in the following section, we read out the Developer instance related to the currently running thread, which is equivalent to reading multiple pieces of data without interference with other threads, and the data value is private. The complete code is as follows:

public class ThreadShareData {

	private static ThreadLocal<Integer> threadIntData = new ThreadLocal<Integer>();

	public static void main(String[] args) {
		for(int i=0;i<2;i++){
			new Thread(new Runnable(){
				public void run() {
					Developer developer = Developer.getThreadInstance();
					int age =  (int) (Math.random()*100);
					developer.age = age;
					developer.name = age+"gxw";
					
		            //read
					DataReadA dataReadA = new DataReadA();
					dataReadA.get();
					DataReadB dataReadB = new DataReadB();
					dataReadB.get();
				}
			}).start();
		}
	 }
	/**
	 * A modular
	 * @author xw.gao
	 * Read the variable data used in the thread
	 */
	static class DataReadA{
		public void get(){
			
			Developer developer = Developer.getThreadInstance();
			int age = developer.getAge();
			String name = developer.getName();

			System.out.println("DataReadA " + Thread.currentThread().getName() 
					+ "age :" + age+",name="+name);
		}
	}
	/**
	 * B modular
	 * @author xw.gao
	 * Read the variable data used in the thread
	 *
	 */
	static class DataReadB{
		public void get(){
			Developer developer = Developer.getThreadInstance();
			int age = developer.getAge();
			String name = developer.getName();

			System.out.println("DataReadB " + Thread.currentThread().getName() + "age :" + age+",name="+name);
		}		
	}
		
	static class Developer{
		String name;
		int age;
		static ThreadLocal<Developer> threadDeveloper = new ThreadLocal<Developer>();

		private Developer(){}
		static public Developer getThreadInstance(){
			Developer developerInstance = threadDeveloper.get();
			if(developerInstance == null){
				developerInstance = new Developer();
				threadDeveloper.set(developerInstance);
			}
			return developerInstance;
		}
		public String getName() {
			String name = threadDeveloper.get().name;
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public int getAge() {
			int age = threadDeveloper.get().age;
			return age;
		}
		public void setAge(int age) {
			this.age = age;
		}
		
	}
}

The operation log is as follows:

DataReadA Thread-0age :10,name=10gxw

DataReadA Thread-1age :56,name=56gxw

DataReadB Thread-1age :56,name=56gxw

DataReadB Thread-0age :10,name=10gxw

We found that the Developer objects read by thread 0 and thread 1 do not interfere with each other and are independent, that is, the functions of sharing variables within the thread and storing and reading multiple independent fields are realized.

Topics: Java Back-end