我的ThreadLocal包含并始终返回null

时间:2015-08-12 07:37:01

标签: java multithreading concurrency thread-local

我想知道当我将threadlocal.set()设置为32个元素的集合时,它是如何存储数据的。 ThreadLocal.get()始终返回null;对应的FutureTask对象有一个结果属性= NullPointerException。知道为什么ThreadLocal无法存储集合项吗?

public class MyCallable<T> implements Callable<Collection<T>> {

    public MyCallable( Collection<T> items ){
        tLocal = new ThreadLocal<Collection<T>>();
        tLocal.set( items );                    //SETS NULL ALTHOUGH the PARAMETER CONTAINS 32 ITEMS
    }

    @Override
    @SuppressWarnings("unchecked")
    public Collection<T> call() throws Exception {
        synchronized( lock ){
            ArrayList<T> _items = new ArrayList<T>();
            ArrayList<T> _e = ( ArrayList<T> ) tLocal.get();   //RETURNS NULL
            for( T item : _e ){
                _items = getPValue( item ));
            }
            return _items ;
        }
    }

    private ThreadLocal<Collection<T>> tLocal;

    private final Object lock = new Object();
}

用法摘要:

List<Future<Collection<T>>> futures = new ArrayList<Future<Collection<T>>>();
ExecutorService pool = Executors.newFixedThreadPool( 8 );

        for( int x = 0; x < numBatches; ++x ){
            List<T> items = retrieveNext32Items( x );
            futures.add( pool.submit( new MyCallable<T>( items ));
        }

        pool.shutdown();

        for( Future<Collection<T>> future : futures ) {
            _items.addAll( future.get() );                  //future.outcome = NullPointerException 
        }

        return _items
}

2 个答案:

答案 0 :(得分:4)

在主线程中创建MyCallable类型的对象,然后将它们提交给线程池。因此,MyCallable的构造函数在一个线程中调用,而方法call在另一个线程中调用。线程本地为每个线程保留一个单独的数据,因此难怪你得到空值。

我不明白为什么你使用本地线程。 items应该是MyCallable中的一个简单字段。如果您修改集合,可能最好将其复制到新集合中。

答案 1 :(得分:0)

存储在本地线程中的值存储在特定线程中。因此,如果您将一个值存储在特定线程t1的本地线程中,并尝试使用相同的本地线程从另一个线程t2获取该值...您将不会获得该值但将获得null。检查在本地线程中设置值的线程是否与从本地线程检索值的线程相同