例如:
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));
}
});
}
DateFormat
类被记录为不是同步类,但如果我们只使用格式方法,它就不能改变整个类的状态?
假设它被声明为私有,如何确保代码是线程安全的?
修复此代码的最佳方法是什么?:
为每个帖子使用不同的实例。
使用同步块。
答案 0 :(得分:4)
因此,DateFormat
类不线程安全。文档具体说:
日期格式未同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问格式,则必须在外部进行同步。
声明字段private
使不使您的实现成为线程安全的。 private
只是说外面的课程无法看到该字段。让我们来看看你的方法:
for (int i=0;i<10;i++)
new Thread(new Runnable(){
public void run(){
System.out.println(df.format(date));
}
});
您创建的Runnable
个对象是匿名类。匿名类是内部类,可以访问其周围类的私有字段。如果不是这样,您的程序将无法编译 - 他们无法访问df
字段。
但他们可以。所以实际上你有10个线程都在访问你的DateFormat
对象,由df
引用。由于我们已经知道DateFormat
不是线程安全的,因此您的程序不是线程安全的。
df
的对象。你没有给出类声明所以我不知道它是什么名字是)。它们引用了同一个类的实例。如果他们两个同时拨打format
,则两个人都将使用相同的私有DateFormat.format
运行df
。因此,这不是线程安全的。DateFormat
实例(因此每次调用方法时都有一个新副本)。但要注意匿名课程!在您的示例中,即使df
是format
方法的本地字段,它仍然不是线程安全的,因为您的所有线程都将访问同一副本。答案 1 :(得分:3)
根据文档,声明格式不是线程安全的。
<强>同步强>
日期格式未同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问格式,则必须在外部进行同步。
如何阅读?如果您没有明确保证某些方法是线程安全的(或者它被记录为不安全),那么您就不能对其安全做出任何假设。
但是,如果你真的希望只使用可能不是有状态的单一方法,那么你可以随时创建高并发环境,并在有和没有同步的情况下测试数据完整性。
我对此有类似的问题,使用Ciphers和RSA。 答案显示了一般如何测试java SE类的特定方法的一种方法。但请注意,实现可能随时发生变化,并且通过针对实现细节进行自己的实现,而不是接口可能会在将来导致一些不可预测的问题。
答案 2 :(得分:2)
我知道很难相信,但DateFormat.format()实际上修改了DateFormat的状态。例如,对于SimpleDateFormat:
// Called from Format after creating a FieldDelegate
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
其中calendar
是DateFormat的字段。
因此,我只建议您信任文档。它可能知道你不知道的事情。