说明:参考《Java多线程核心技术》
7、类ThreadLocal
变量值得共享可以使用public static变量的形式,所有的线程都使用同一个public static变量。
ThreadLocal类主要解决的是每个线程板绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。
类ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的值,不同线程中的值是可以放入ThreadLocal类中进行保存的。
public class Tools {
public static ThreadLocal threadLocal = new ThreadLocal();
}
public class ThreadA extends Thread{
int num = 100;
@Override
public void run() {
try {
for (int i = 0; i < num; i++) {
Tools.threadLocal.set("ThreadA" + (i+1));
System.out.println("ThreadA get value = " + Tools.threadLocal.get());
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadB extends Thread{
int num = 100;
@Override
public void run() {
try {
for (int i = 0; i < num; i++) {
Tools.threadLocal.set("ThreadB" + (i+1));
System.out.println("ThreadB get value = " + Tools.threadLocal.get());
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadLocalTest {
public static void main(String[] args) {
int num = 100;
try {
ThreadA threadA = new ThreadA();
ThreadB threadB = new ThreadB();
threadA.start();
threadB.start();
for (int i = 0; i < num; i++) {
Tools.threadLocal.set("Main" + (i+1));
System.out.println("Main get value = " + Tools.threadLocal.get());
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
Main get value = Main1
ThreadA get value = ThreadA1
ThreadB get value = ThreadB1
ThreadB get value = ThreadB2
ThreadA get value = ThreadA2
Main get value = Main2
ThreadB get value = ThreadB3
ThreadA get value = ThreadA3
Main get value = Main3
ThreadA get value = ThreadA4
ThreadB get value = ThreadB4
Main get value = Main4
...
*/
可以看到,每个线程都向threadLocal对象中set()值,但是每个线程获得的值都是自己set()的值,相互之间并不影响。
源码如下:
public T get() {
Thread t = Thread.currentThread(); // 当前线程
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread(); // 当前线程
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ReentrantLock实现同步1
public class ReentrantLock {
int num = 5;
private Lock lock = new java.util.concurrent.locks.ReentrantLock();
public void reentrantLockMethod() {
lock.lock();
for (int i = 0; i < num; i++) {
System.out.println("ThreadName = " + Thread.currentThread().getName() + (" " + (i + 1)));
}
lock.unlock();
}
}
public class MyThread extends Thread{
private ReentrantLock reentrantLock;
public MyThread(ReentrantLock reentrantLock) {
super();
this.reentrantLock = reentrantLock;
}
@Override
public void run() {
reentrantLock.reentrantLockMethod();
}
}
public class ReentrantLockTest {
public static void main(String[] args) {
ReentrantLock reentrantLock = new ReentrantLock();
MyThread myThread = new MyThread(reentrantLock);
MyThread myThread1 = new MyThread(reentrantLock);
MyThread myThread2 = new MyThread(reentrantLock);
myThread.start();
myThread1.start();
myThread2.start();
}
}
/**
ThreadName = Thread-0 1
ThreadName = Thread-0 2
ThreadName = Thread-0 3
ThreadName = Thread-0 4
ThreadName = Thread-0 5
ThreadName = Thread-2 1
ThreadName = Thread-2 2
ThreadName = Thread-2 3
ThreadName = Thread-2 4
ThreadName = Thread-2 5
ThreadName = Thread-1 1
ThreadName = Thread-1 2
ThreadName = Thread-1 3
ThreadName = Thread-1 4
ThreadName = Thread-1 5
*/
结果表明:当前线程持有锁,因此不会出现交叉打印,但是线程之间的顺序是随机的。
ReentrantLock同步测试2:
public class SynchroReentrant {
private Lock lock = new ReentrantLock();
public void synchroReetrantServiceA() {
try {
lock.lock();
System.out.println("methodA name = " + Thread.currentThread().getName() +
" start time = " + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("methodA name = " + Thread.currentThread().getName() +
" end time = " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void synchroReetrantServiceB() {
try {
lock.lock();
System.out.println("methodB name = " + Thread.currentThread().getName() +
" start time = " + System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("methodB name = " + Thread.currentThread().getName() +
" end time = " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class ThreadA extends Thread{
private SynchroReentrant reentrant = new SynchroReentrant();
public ThreadA(SynchroReentrant reentrant) {
super();
this.reentrant = reentrant;
}
@Override
public void run() {
reentrant.synchroReetrantServiceA();
}
}
public class ThreadAA extends Thread{
private SynchroReentrant reentrant = new SynchroReentrant();
public ThreadAA(SynchroReentrant reentrant) {
super();
this.reentrant = reentrant;
}
@Override
public void run() {
reentrant.synchroReetrantServiceA();
}
}
public class ThreadB extends Thread{
private SynchroReentrant reentrant = new SynchroReentrant();
public ThreadB(SynchroReentrant reentrant) {
super();
this.reentrant = reentrant;
}
@Override
public void run() {
reentrant.synchroReetrantServiceB();
}
}
public class ThreadBB extends Thread{
private SynchroReentrant reentrant = new SynchroReentrant();
public ThreadBB(SynchroReentrant reentrant) {
super();
this.reentrant = reentrant;
}
@Override
public void run() {
reentrant.synchroReetrantServiceB();
}
}
public class SynchroReetrantTest {
public static void main(String[] args) throws InterruptedException {
SynchroReentrant reentrant = new SynchroReentrant();
ThreadA threadA = new ThreadA(reentrant);
threadA.start();
ThreadAA threadAA = new ThreadAA(reentrant);
threadAA.start();
Thread.sleep(200);
ThreadB threadB = new ThreadB(reentrant);
threadB.start();
ThreadBB threadBB = new ThreadBB(reentrant);
threadBB.start();
}
}
/**
methodA name = Thread-0 start time = 1546965577580
methodA name = Thread-0 end time = 1546965580591
methodA name = Thread-1 start time = 1546965580591
methodA name = Thread-1 end time = 1546965583602
methodB name = Thread-2 start time = 1546965583602
methodB name = Thread-2 end time = 1546965586612
methodB name = Thread-3 start time = 1546965586612
methodB name = Thread-3 end time = 1546965589623
*/
说明:持有了锁,其他的线程只能阻塞,然后再次争抢执行,但是线程之间执行的顺序是无序的。