匿名runnable类中的变量始终是线程安全的吗?

时间:2012-11-30 03:13:23

标签: java multithreading interface concurrency runnable

我创建了一个类UnSafeTask:

package com.threads;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class UnsafeTask implements Runnable {
    private Date startDate;

    @Override
    public void run() {
        startDate = new Date();
        System.out.printf("Starting Thread: %s : %s\n", Thread.currentThread().getId(), startDate);
        try {
            TimeUnit.SECONDS.sleep((int) Math.rint(Math.random() * 10));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("Thread Finished: %s : %s\n", Thread.currentThread().getId(), startDate);
    }    
}

我在类Core中使用它如下:

package com.threads;

import java.util.concurrent.TimeUnit;

public class Core {

    public static void main(String[] args) {
        UnsafeTask task = new UnsafeTask();

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(task);
            thread.start();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果如预期的那样(变量由线程共享)。当我按如下方式重构Core以使用匿名的runnable类时:

package com.threads;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class Core {

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Runnable() {
                Date startDate = new Date();

                @Override
                public void run() {
                    startDate = new Date();
                    System.out.printf("Starting Thread: %s : %s\n", Thread.currentThread().getId(), startDate);
                    try {
                        TimeUnit.SECONDS.sleep((int) Math.rint(Math.random() * 10));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.printf("Thread Finished: %s : %s\n", Thread.currentThread().getId(), startDate);    
                }    
            });
            thread.start();
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

现在变量(startDate)是线程安全的。在这种情况下,为什么变量线程是安全的?提前谢谢。

4 个答案:

答案 0 :(得分:3)

在第一个示例中,您有一个Runnable实例(在所有线程中共享)。在你的第二个例子中,你有10个Runnable实例,每个Thread有1个实例(没有共享,因此,线程安全)。

答案 1 :(得分:1)

线程安全不依赖于类是否具有名称。在第一种情况下,您在所有线程中共享命名类的实例;您可以轻松地与您的第二个匿名课程做同样的事情!

此外,您可以在匿名类的实例之间共享在外部作用域中声明的final个变量。尽管变量必须是final,但并不意味着它的实例将是 immutable 。在这种情况下,匿名类肯定是非线程安全的。

所以标题问题的答案是“不,并非所有匿名类都是线程安全的”。无论是否命名,您都需要明确设计具有线程安全性的类。

答案 2 :(得分:0)

匿名或不跟匿的类与线程安全无关。

匿名类就像普通类一样,除了它的源不存在于自己的.java文件中(以及其他一些非常小的东西)。

答案 3 :(得分:0)

请注意,您的第二个示例与第一个示例相同:

public static void main(String[] args) {

    for (int i = 0; i < 10; i++) {
        // Task object instantiation now inside for loop:
        UnsafeTask task = new UnsafeTask();   
        Thread thread = new Thread(task);