如何在父对象中同步(d)方法和修改对象的属性?

时间:2009-08-12 06:36:02

标签: java concurrency multithreading

我有两个从控制器类运行的线程。第一个线程接收SMS消息,并且只要程序处于启动状态,就应该继续运行。另一个线程用于计算GPS位置单位。

控制器启动SMS线程并等待文本消息。如果文本消息符合特定条件,则启动GPS定位线程并将坐标发送回控制器。

对于每个帖子,我使用了以下格式:

reader = new Reader(this);
        new Thread(reader).start();

然后读者类使用控制器的引用,以便它可以调用控制器中的方法:

public void ReceivedCommand(String address) {
    [..]
}

然后,此方法创建一个GPS线程实例,该实例从父对象(线程?)调用一个名为ReceivedLocation的方法,然后设置新的SMS消息(TextMessage对象)。问题是,SMS线程只能返回原始发件人的地址(回复),我需要使用GPS线程,以便我可以设置SMS消息的有效负载。

所以现在我有2个方法使用相同的对象(TextMessage对象),但我想确保第一个方法(SMS地址设置器)在GPS线程获取GPSLocation时不会改变地址设置。

可以同步ReceivedCommand()中的块:

  • 将地址添加到TextMessage对象
  • 运行GPS线程
  • 让GPS线程调用第二种方法(ReceivedLocation()
  • 让该方法更改TextMessage对象?

1 个答案:

答案 0 :(得分:4)

首先,线程创建很昂贵。您可能最好使用线程池(可以在java.util.concurrent包中找到(ExecutorService)并将您的工作转移到

在共享对象上使用synchronized将确保同时没有两个线程 synchronized 。但是,如果我在synchronized块中创建并启动一个线程,我(即第一个线程)可能在第二个线程实际启动之前退出该块:

final TextMessage msg = //...
Thread t = new Thread(r);
synchronized (msg) {
    t.start();
} //the other thread is still running and now this thread has not synchronized on the msg

然后你的处理器r:

Runnable r = new Runnable() {
    public void run() {
        synchronized (msg) { //only any use if readers are alse sync-ed
            msg.setGpsLocation(findGpsLocation(msg)); 
        }
    }
}

只要TextMessage对象是线程安全的(即字段访问是synchronized),你应该没问题,不需要以这种方式显式同步

  

请注意,synchronized在语义上非常重要,不仅仅是从线程调度的角度,而且还来自 it affects data visibility between threads 这一事实(例如,没有同步,你不能确保在一个线程中进行的修改对另一个线程可见。

修改我的答案以使用ExecutorService

final TextMessage msg = //...
ExecutorService worker = Executors.newSingleThreadedExecutor();
Future<?> f = worker.submit(r); //the future represents the work

在这里,r看起来像是:

Runnable r = new Runnable() {
    public void run() {
        GpsLocation  loc = findGpsLocation(msg);
        msg.setGpsLocation(loc); //the setter is synchronized
    }
}

setGpsLocation方法应为synchronized(以及getter以及两个线程所需的任何其他字段访问)。请注意,如果跨字段需要原子性,那么简单地同步字段访问并不总是足够的。例如,您可能希望有条件地更新另一个字段的值 - 在这种情况下,只要您在字段访问期间明确synchronize,一切都会正常:

synchronized (msg) {
    if (msg.getGpsLocation().isIn(AMERICA))
       msg.append(" DUDE!")
}