Android:如何创建2维数组的副本以供在另一个线程中使用?

时间:2013-08-23 08:04:56

标签: java android arrays multithreading android-asynctask

我创建了一个基本的日志记录类,当前它是一个2维数组,它存储多达100个事件的日志信息(然后开始覆盖信息,所以我只保留最后100个事件)。

在某个级别的日志事件上,此数组数据将转储到AsyncTask线程的数据库中。

目前,数组是在类级别定义的,因此AsyncTask线程正在访问GUI线程正在访问的同一个数组(它正在给我NullPointerExceptions,因为它应该)。

我需要一种方法来复制AsyncTask线程启动瞬间的数组值,这样后台线程就可以读取所有数据并将其正确发送到数据库 - 这就是重点我被困在了。

// Defined in the class
private static String[][] logHistory = new String[100][6];


// Class to log errors to a database
private static class asyncLog extends AsyncTask<Void,Void,Void>
{
    // This is the background thread
    @Override
    protected Void doInBackground(Void... params)
    {
        Thread.currentThread().setName("LogToDB.asyncLog.doInBackground");              

        // Make a copy of the array in its current state
        final String[][] logTemp = new String[100][6];
        for (int i = 0; i < 100; i++) 
        {
              for (int j = 0; j < 6; j++) 
              {
                logTemp[i][j]=logHistory[i][j];
              }
        }

        // ...snip
    }
}

显然最终修饰符在这里是错误的,因为我仍然得到异常

我想知道:

  • 这是我正在尝试做的正确方法吗?
  • 如果没有,有什么更好的方式?
  • 如何在后台线程中复制字符串数组,这样无论GUI线程对原始数组做了什么更改,副本总是具有相同的值,直到线程结束并被销毁

我见过很多关于处理1D数组的例子,但这些数据主要是int数据类型(例如this one,而且我理解字符串,它们总是引用:/

EDIT 根据要求,请参阅堆栈跟踪:

08-23 09:17:35.570: E/AndroidRuntime(8030): FATAL EXCEPTION: LogToDB.asyncLog.doInBackground
08-23 09:17:35.570: E/AndroidRuntime(8030): java.lang.RuntimeException: An error occured while executing doInBackground()
08-23 09:17:35.570: E/AndroidRuntime(8030):     at android.os.AsyncTask$3.done(AsyncTask.java:299)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at java.util.concurrent.FutureTask.run(FutureTask.java:239)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at java.lang.Thread.run(Thread.java:856)
08-23 09:17:35.570: E/AndroidRuntime(8030): Caused by: java.lang.NullPointerException
08-23 09:17:35.570: E/AndroidRuntime(8030):     at coty.production.downtimeaquisition.LogToDB.Insert(LogToDB.java:393)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at coty.production.downtimeaquisition.LogToDB.access$10(LogToDB.java:387)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at coty.production.downtimeaquisition.LogToDB$asyncLog.doInBackground(LogToDB.java:558)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at coty.production.downtimeaquisition.LogToDB$asyncLog.doInBackground(LogToDB.java:1)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
08-23 09:17:35.570: E/AndroidRuntime(8030):     at java.util.concurrent.FutureTask.run(FutureTask.java:234)
08-23 09:17:35.570: E/AndroidRuntime(8030):     ... 4 more

LogToDB.java:558是对Insert方法的调用

LogToDB.java:387是Insert方法

LogToDB.java:393是突出显示的行:

Statement stmt=null;

try 
{
    stmt=dbConn.createStatement(); // This line
    stmt.executeUpdate(sql);
}  

1 个答案:

答案 0 :(得分:1)

我要假设你要做的就是有一个事件的“虚拟日志”,只有在出现某些不良情况时才会被丢弃,这样你就不会把你的主日志弄得乱七八糟但是每当发生错误时都能看到细节。如果是这样的话,我就是这样做的:

  1. 定义一个类LogMessage,其中包含有关您的消息的必要信息,通常是String和日志级别(应该是enum),可能包含{{{}的字段1}}。有关此接口通常的外观示例,请参阅log4j和slf4j。
  2. 定义固定长度的缓冲类;遗憾的是,虽然1.6并发API具有支持固定长度队列的接口,但我无法找到一个好的,高效的实现。最佳选择在很大程度上取决于读取和转储的频率,但我首先要做的事情是分配固定大小的数组,使用Throwable作为数组索引。标准(无限大小)实现基于the paper "Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms"。对此数组的引用必须为AtomicInteger或由volatile支持。
  3. 当跟踪日志级别的“漏斗”API看到具有适当重要性的日志消息时,它会以原子方式交换整个日志结构并触发作业以转储它。如果您正在登录会被多个日志线程混淆的设施,您甚至可能将整个日志缓冲区提交到单个长时间运行的转储线程读取的AtomicReference