2013-07-22 33 views
0

我想实现一个耗时的任务的异步返回。所以任务数据被插入Q中,并立即返回。一堆20个线程从该数据队列中获取任务。但是线程中的数据变为空,我不知道为什么。Java线程问题,我得到一个null,而执行一个异步任务

代码段的(唯一相关的代码部分)

定义

private static LinkedList<Object[]> cacheQ = new LinkedList<Object[]>(); 
private static ArrayList<Thread> cacheThreads = null; 

一次初始化

if (cacheThreads == null) { 
     cacheThreads = new ArrayList<Thread>(); 
     for (i = 0; i < 20; i++) { 
      CacheThread cacheThread = readWriteOps.new CacheThread(); 
      Thread thread = new Thread(cacheThread); 
      cacheThreads.add(i, thread); 
      thread.start(); 
     } 
     System.out.println("CAche Threads Started!"); 
    } 

在开始添加新的任务交给了Q(addFirst

public void arrayizeToCache(String key, CacheData value) { 
    synchronized (cacheThreads) { 
     Object[] tuple = new Object[SIZE] ; 
     tuple[KEY] = key ; 
     tuple[VALUE] = value ; 
----NOT NULL----log.debug("CacheThread arrayizeToCache k"+key+"v"+value) ; 
     cacheQ.addFirst((Object[])tuple); 
     cacheThreads.notify(); 
    } 
} 

线程

public class CacheThread implements Runnable { 
    @Override 
    public void run() { 
     System.out.println("CachedThread running!"); 
     CacheData cacheStore = null; 
     while (true) { 
      try { 
       String key; 
       synchronized (cacheThreads) { 
        if (cacheQ.isEmpty()) { 
         log.debug("Cache Q waiting"); 
         cacheThreads.wait(); 
        } 
        if (cacheQ.isEmpty()) { 
         log.error("Cache List empty nothing to cache"); 
         continue; 
        } 
        Object[] cacheData = (Object[]) cacheQ.removeLast(); 
        key = (String) cacheData[KEY] ; 
        cacheStore = (CacheData) cacheData[VALUE]; 
----- HERE ----- 
//More code, but irrelevant for this question. 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      // log.debug(((Runnable) this).toString() + 
      // "Server : flush SUCCESS"); 
     } 
    } 
} 

的实际工作在-----HERE-----我得到一个空的cacheStore.getValue()。我在这里错过了什么。基本的东西。

我已经使用了LinkedList,因此在结构上它应该工作。链表包含我需要处理的数据。它拥有一个Object数组,因为我有超过1个数据元素。

编辑:再次

private static final int KEY = 0 ; 
private static final int VALUE = 1 ; 
private static final int SIZE = 2 ; 

编辑: 这是我如何打电话arrayize

ReadWriteOperations.getInstance(this).arrayizeToCache(key, 
      new CacheData(subscription, SuperCache.NEVER_EXPIRE)); 

我CacheData对象

public class CacheData { 
private Object value ; 
private Integer expiry = 0 ; 
public CacheData(Object newValue) { 
    value = newValue ; 
} 
public CacheData (Object newValue, Integer newExpiry) { 
// THIS LINE WAS MISSING  value = newValue ; 
    expiry = newExpiry ; 
} 
public Object getValue() { 
    return value ; 
} 
public Integer getExpiry() { 
    return expiry ; 
} 
} 

答:我是在所有的初始化值。有点认为这将是一个更复杂的事情。而且这里的凌晨2点:)感谢@Gray。

+2

您应该考虑对此使用'ExecutorService'。通过分配自己的线程,然后从作业队列中读取数据,实际上就是在重写它们。请参阅:http://docs.oracle.com/javase/tutorial/essential/concurrency/exinter.html – Gray

+0

如果您不移至“ExecutorService”,则应将“cacheQ”队列切换为“BlockingQueue”它负责同步,通知/等待等。 – Gray

+0

我将链接列表更改为ConcurrentLinked和LinkedBlockingQueue,两者都不起作用。同样的结果。此处还有其他事情。 – taxeeta

回答

1

你的代码对我来说看起来很好。我很想知道:

  • cacheStore的值在哪里更新?
  • 线程启动后是否更新?这可能是问题所在。
  • 如果是这样,则需要更新synchronized (cacheThreads) {块的内部,以使更改对正在运行的线程可见。

以下是有关代码中的一些补充意见:

  • 你分叉你自己的线程,然后有一个​​LinkedList的工作。我鼓励你看看那两个都可以做到的ExecutorService patterns。绝对推荐用于大多数线程任务。

  • 如果没有移动到ExecutorService,你应该切换您的cacheQ队列是一个BlockingQueue这需要照顾​​的,notify()/wait()等你。

+0

在这里,再次感谢。我现在可以睡了,明天解决客户问题。 – taxeeta

相关问题