【问题标题】:Do I need to synchronize in this situation在这种情况下我需要同步吗
【发布时间】:2014-03-30 17:54:58
【问题描述】:

我正在制作 Android 应用程序。我有一门课,我每 30 秒从数据库中获得一些订单,如下所示:

public class OrderScheduler {
    private List<OrderMain> orders = Collections.synchronizedList(
            new ArrayList<OrderMain>());
    ...
    private void main() {
        service.scheduleAtFixedRate(new Runnable() {
            public void run() {
                orders = getStuff();
            }
        }, 0, 30, TimeUnit.SECONDS);
    }
}

然后有一个 Activity 类,我在其中使用上面列表中的对象创建 ListView,如下所示:

newOrdersListView = (ListView) findViewById(R.id.newOrdersListView);
    OrderScheduler os = OrderScheduler.getInstance();
    List<OrderMain> newOrders = (os.getOrders() == null) ? 
            new ArrayList<OrderMain>() : os.getOrders();
    ArrayAdapter<OrderMain> listAdapter = new ArrayAdapter<OrderMain>(
            this, R.layout.listview_row, newOrders);
    newOrdersListView.setAdapter(listAdapter);

我在迭代同步列表时读取了 javadoc,我需要对其进行同步。

我的问题是当我单击此列表视图的某些项目时,onItemClick 方法是否需要在同步块中?我认为当我从 listview 中选择一些项目时,它基本上需要遍历 newOrders 列表。

顺便说一句,现在我不同步这个监听器方法,它似乎工作。在此应用程序中,我创建的线程数不超过 OrderScheduler 中的线程数。 感谢您的帮助。

【问题讨论】:

    标签: java android multithreading listview


    【解决方案1】:

    看起来您的 .getStuff() 方法每次都会生成一个完全不同的列表;看起来它的结果只有一个消费者。此外,消费者似乎没有修改结果。

    因此,我的建议是使用AtomicReference

    你的“生产者”代码会这样做:

    ref.set(getStuff());
    

    和你的“消费者”:

    List<OrderMain> newOrders = ref.get();
    

    您的ref 将是生产者和消费者之间共享的AtomicReference&lt;List&lt;OrderMain&gt;&gt;

    【讨论】:

    • 引用分配在 Java 中是原子的,因此无需使用 AtomicReference 使其过于复杂。 AtomicReference 的主要力量来自 compareAndSet() 和 getAndSet()。如果只使用 set() 和 get() 则没有附加功能。
    • @kupsef 是它的原子属性使它在这种情况下有用!
    • @kupsef 还有,“引用分配在 Java 中是原子的”volatile,否则您没有这样的保证;除非我弄错了,否则您不能在其声明类之外共享 volatile 引用。
    • 好吧,引用分配是原子的。如果您不相信,请进行一些研究:)
    • 好吧我有点困惑,因为我第一次看到它。我改变了你的建议,它似乎工作正常。但我不知道它对我之前的解决方案有什么影响。好点吗 ?无论如何,非常感谢!
    【解决方案2】:

    使用当前代码,您无需同步任何内容,因为您每次都创建一个 ArrayList(如果您使用迭代器,因为在内部它将使用旧的 ArrayList)。

    您需要在迭代时同步列表的原因是因为您可以获得ConcurrentModificationException(迭代器不允许您在阅读时对列表进行任何更改)

    P.S 我想getStuff 会创建一个新的ArrayList,因为您执行orders = getStuff();,如果您更改代码以修改您的ArrayList,您将看到ConcurrentModificationException 异常。

    【讨论】:

    • 谢谢你的回答!是的,我不会在 OrderScheduler 之外的任何地方更改此列表,因此我不会遇到此异常。
    【解决方案3】:

    问问自己是谁在执行 onItemClick。

    它是主 (UI) 广告,所以无论发生什么,用户有多疯狂/多快,事件都会被串行处理(由主线程)。

    同步不会有任何影响。

    【讨论】:

    • 是的,正如你所说的是用户,所以是这个应用程序的主线程。所以你说在我原来的解决方案中,列表不需要同步列表?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 1970-01-01
    相关资源
    最近更新 更多