TimerTask中的所有内容都需要是线程安全的吗?
示例
@Autowired
private MySweetService mySweetService;
int delaySeconds = 0;
int intervalMinutes = 1;
for(int i=0; i<5; i++) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
// This method below is my questionable area
mySweetService.doStuff(i);
}
}, delaySeconds, intervalMinutes);
}
在TimerTask匿名类中,一切都需要是线程安全的吗?任何固有的问题?
答案 0 :(得分:2)
没有。
对于每个Timer
,都有一个线程。计时器一次只能执行一个任务。
见Timer
因此mySweetService.doStuff
方法不需要是线程安全的。
修改:问题已被修改。最初在循环外只创建了一个Timer
实例,因此只有一个线程。
现在它在循环中创建Timer
;上述内容不再适用:
每个Timer
都有自己的线程,可能会出现竞争条件。这非常相当于使用Thread
或Runnable
。
答案 1 :(得分:2)
现在你有5个线程,我们知道调用doStuff,循环中创建的Timer线程。如果多个线程与方法交互而不是同时调用同一方法,那么显然需要考虑线程安全性。
但是单个线程调用方法不足以提供线程安全性。请考虑以下代码:
private int value;
void add(int x) {
value+=x;
}
void sub(int x) {
value-=x;
}
给定2个线程,每个线程调用其中一个方法,代码显然不是线程安全的。
重点是:线程安全是关于状态,而不是方法。
答案 2 :(得分:0)
“如果TimerTask访问也由其他应用程序线程访问的数据,则不仅TimerTask必须以线程安全的方式访问,而且其他访问该数据的其他类也必须这样做。通常,最简单的方法是实现此目的这是为了确保TimerTask访问的对象本身是线程安全的,从而将线程安全性封装在共享对象中。”-Java并发性实践第1.4章
是 TimerTask中的所有内容都必须是线程安全的。在您的示例中,有5个线程同时调用mySweetService.doStuff(),并且是否存在非线程安全的集合像HashMap一样,可能会导致意外行为。
根据经验法则,任何并发调用或对变量或集合的访问都必须是线程安全的。如果我错了,请纠正我
“对象是否需要线程安全取决于它是否将从多个线程访问。这是对象在程序中的使用方式的属性,而不是它的用途。使对象成为线程安全的对象需要使用同步来协调访问其可变状态; <strong>不这样做可能会导致数据损坏和其他不良后果”。-Java Concurrency in Practice-第2章
这本书可能解答了所有问题:P
答案 3 :(得分:0)
目前还不清楚您还在哪里使用mySweetService。如果在多个线程中使用它,则mySweetService.doStuff(i);必须是线程安全的。更准确地说,该方法内部的每个数据结构都必须以线程安全的方式正确使用,并且内部逻辑必须是线程安全的。最简单的方法是使do Stuff同步。但是,如果以其他未同步的方法使用mySweetService内部的数据,那也将是一个问题。
因此,您真正关心的不是计时器回调内部的逻辑,而是服务本身内部的逻辑。
我希望有帮助。
迈克尔, 并发硕士课程作者 https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY