我有两个从控制器类运行的线程。第一个线程接收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
对象ReceivedLocation()
)答案 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!")
}