在多线程编程中,解决线程之间的协作、数据共享等问题,不可避免需要用到volatitle、synchronize、Condition、ThreadLocal等,接下简单介绍一下:
一、volatitle
主要解决线程间数据可见性及指令重排序,具体可以参考volatitle随记,这里不在详细介绍。
二:Condition
Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,阻塞队列实际上是使用了Condition来模拟线程间协作,Condition是一个接口,它提供了以下几个方法:
void await() throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
long awaitNanos(long nanosTimeout) throws InterruptedException;
void awaitUninterruptibly();
void signal();
void signalAll();
- Condition基本的方法就是await()和signal()方法;
- Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition().
- 调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用。
- Conditon中的await()对应Object的wait(),Condition中的signal()对应Object的notify();Condition中的signalAll()对应Object的notifyAll()。
示例代码如下:
public class ConditionTest {
public final static Lock lock = new ReentrantLock();
public final static Condition condition = lock.newCondition();
public static void main(String[] args) {
new Consumer().start();
new Producer().start();
}
public static class Consumer extends Thread{
public void run(){
while(true){
consume();
}
}
private void consume(){
lock.lock();
System.out.println("wait singal..");
try {
condition.await();
System.out.println("consume..");
} catch (InterruptedException e) {
}finally{
lock.unlock();
}
}
}
public static class Producer extends Thread{
public void run(){
while(true){
product();
}
}
private void product(){
try{
lock.lock();
Thread.sleep(100);
System.out.println("product...");
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
}
-
Condition的执行方式,是当在线程Consumer中调用await方法后,线程Consumer将释放锁,并且将自己沉睡,等待唤醒,线程Producer获取到锁后,开始做事,完毕后,调用Condition的signalall方法,唤醒线程Consumer,线程Consumer恢复执行。
-
以上说明Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。
三:ThreadLocal
多线程并发执行时,需要数据共享,所以才有volatitle变量解决线程之间数据共享问题,也有了锁的同步机制,确保数据的准确性,而有的时候,线程数据并不需要共享,只需要线程自己维护即可,而ThreadLocal就是用来做线程之间数据隔离的,在介绍ThreadLocal使用前,简单了解一下源码:
先我们来看一下ThreadLocal类是如何为每个线程创建一个变量的副本的。
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();//1
ThreadLocalMap map = getMap(t);//2
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();//3
}
- 1、第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。
- 2、获取到Entry键值对,注意这里获取Entry时参数传进去的是 this,即ThreadLocal实例,而不是当前线程t。如果获取成功,则返回value值。
- 3、如果map为空,则调用setInitialValue方法返回value。
接下来看一下ThreadLocalMap这个类:
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
总结:
- 在每个线程Thread内部有一个ThreadLocalMap类型的成员变量threadLocals。
- ThreadLocalMap成员变量的Entry的Key为,当前ThreadLocal变量的WeakReference封装,value为变量。
使用示例:
public class ThreadLocalTest {
private ThreadLocal<Map<String,String>> paramsLocal = new ThreadLocal<Map<String,String>>();
public void validate(Request request) throws ApiRuleException {
try{
if(paramsLocal.get() == null){
paramsLocal.set(new HashMap<>());
}
Map<String,String> params = paramsLocal.get();
params.put("source","source");
params.put("source1","source1");
//做其它事情
}finally{
paramsLocal.get().clear();//清除Map数据
}
}
}
网友评论