如何知道Java SE类或方法是否是线程安全的?

Nas*_*LEK 7 java multithreading thread-safety

例如:

static private DateFormat df = new SimpleDateFormat();
public static void format(final Date date) { 
   for (int i = 0; i < 10; i++) 
     new Thread(new Runnable() {
         public void run() {
             System.out.println(df.format(date));
         } 
     });
}
Run Code Online (Sandbox Code Playgroud)

DateFormat类记录为不同步类,但如果我们只使用格式方法,它不能改变整个阶级的地位?

假设它被声明为私有,如何确保代码是线程安全的?

修复此代码的最佳方法是什么?:

  1. 为每个线程使用不同的实例.

  2. 使用同步块.

Rea*_*tic 7

  • 对于标准 Java SE 类,了解该类是否线程安全的最佳方法是仔细阅读其文档。始终阅读类文档和方法文档。如果有人说它不是同步的或不是线程安全的,你就知道它不是线程安全的。
  • 因此,DateFormat该类不是线程安全的。文档特别指出:

    日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一个格式,则必须在外部进行同步。

  • 声明一个字段private没有让你实现线程安全的。private只是说外面的班级看不到那个领域。让我们看看你的方法:

     for (int i=0;i<10;i++) 
         new Thread(new Runnable(){
             public void run(){
                 System.out.println(df.format(date));
             } 
         });
    
    Run Code Online (Sandbox Code Playgroud)

    Runnable您创建的对象是匿名类。匿名类是内部类,可以访问其周围类的私有字段。如果不是这样,您的程序将无法编译 - 他们无法访问该df字段。

    但他们可以。因此,实际上您有 10 个线程都在访问您的一个DateFormat对象,由df. 既然我们已经知道,DateFormat不是线程安全的,你的程序是不是线程安全的。

  • 此外,如果两个外部线程引用了您的对象(我的意思是包含df内部的对象。您没有提供类声明,所以我不知道它的名称是什么)。他们引用了你的类的同一个实例。如果两者同时调用format,则两者都将DateFormat.format使用相同的 private运行df。因此,这不会是线程安全的。
  • 为了线程安全,您需要在对象上进行同步或使用某种其他类型的锁(一个锁用于访问它的所有可能线程),这正是文档所说的。
  • 另一种方法是拥有一个完全本地的对象,它只对一个线程可见。不是一个字段 - 一个局部变量,它可以访问一个唯一创建的实例DateFormat(因此每次调用该方法时都会有一个新副本)。不过要小心匿名类!在您的示例中,即使df是该format方法的本地字段,它仍然不是线程安全的,因为您的所有线程都将访问相同的副本。