TimerTask中的所有内容都需要是线程安全的吗?

时间:2014-06-11 20:34:55

标签: java multithreading timertask

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匿名类中,一切都需要是线程安全的吗?任何固有的问题?

4 个答案:

答案 0 :(得分:2)

没有。 对于每个Timer,都有一个线程。计时器一次只能执行一个任务。 见Timer

因此mySweetService.doStuff方法不需要是线程安全的。

修改:问题已被修改。最初在循环外只创建了一个Timer实例,因此只有一个线程。 现在它在循环中创建Timer;上述内容不再适用: 每个Timer都有自己的线程,可能会出现竞争条件。这非常相当于使用ThreadRunnable

答案 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