美文网首页
多线程使用小结

多线程使用小结

作者: 开心就好_4ad7 | 来源:发表于2018-04-17 11:51 被阅读0次

    在多线程编程中,解决线程之间的协作、数据共享等问题,不可避免需要用到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数据
        }
    }
}

相关文章

  • 多线程使用小结

        在多线程编程中,解决线程之间的协作、数据共享等问题,不可避免需要用到volatitle、synchroni...

  • GCD(三) dispatch_group

    本文是GCD多线程编程中dispatch_group内容的小结,通过本文,你可以了解到: 如何使用dispatch...

  • iOS多线程使用小结

    iOS多线程多有文章介绍,API和简单使用细节不再过多赘述.写这篇文章也算是对最近多线程开发中遇到的新奇点做个总结...

  • 多线程的优势

    多线程的优势 尽管使用多线程有挑战,但是由于使用多线程也有很多好处,我们仍然使用多线程。这些优势(好处)是: 更好...

  • 多线程复习笔记

    多线程学习作者:zhuzhu 时间:19/6Part I 多线程技能使用多线程也就是在使用异步。使用多线程技...

  • 多进程和多线程的应用场景

    其实,使用多线程编程还是使用多进程编程,有一个简单的原则,如果能使用多线程实现的,就用多线程,不能使用多线程实现的...

  • iOS实录16:GCD使用小结(二)

    iOS实录16:GCD使用小结(二) iOS实录16:GCD使用小结(二)

  • iOS 通知多线程的使用

    iOS 通知多线程的使用 iOS 通知多线程的使用

  • iOS-多线程

    iOS开发中常用的几种多线程方案,简单做个小结,方便日后查阅。 NSThead GCD NSOperation &...

  • 学习笔记:Java 多线程编程核心技术(第一章)

    Chapter 1 多线程技能 使用多线程 使用多线程有两种方式: 继承 Thread 类重写 run() 方法 ...

网友评论

      本文标题:多线程使用小结

      本文链接:https://www.haomeiwen.com/subject/xddukftx.html