2015-09-25 36 views
1

我有一个类TestLogger,它有一个void方法log(String s),它可以被多个线程访问。这里是我的代码Java多线程:线程安全数据结构与同步方法

public class TestLogger { 
    private static final StringBuffer buffer = new StringBuffer(); 

    public static void log(String s) { 
     buffer.append(s); 
    } 
} 

我不知道在这里如果我使用的线程安全类StringBuffer,我还需要把synchronized关键字的方法log(String),以确保该方法的线程安全?这种方法怎么样

public static void log(String s, int type) { 
    if (type == 0) 
     buffer.append(s); 
    if (type == 1) 
     buffer.append("SOME HEADER " + s); 
} 

这里类型没有在方法日志中修改。我需要使用synchronized关键字吗?

在Java中,同步关键字和线程安全类都可以提供线程安全性。我不确定何时使用其中一个和另一个?

+0

如果使用缓冲区,则不需要同步,如果某些内容是“线程安全”,则一般规则可能使用同步本身 –

回答

2

由于此方法的任何实现最多只能访问buffer一次,因此您在技术上不需要同步该方法,但这是非常糟糕的做法。

首先,它非常脆弱。这是不够,一些粗心的开发人员需要看看这种方法并决定以“优化”它(以更好的Java代码!)你失去了StringBuffer的同步:

public static void log(String s, int type) { 
    if (type == 0) 
     buffer.append(s); 
    if (type == 1) 
     buffer.append("SOME HEADER ").optimize(s); 
} 

这段代码显示了两个单独的呼叫因此,如果您同时拨打log('A', 1)log('B',1),那么您的缓冲区可能会很好,为"SOME HEADER SOME HEADER AB"。其次,即使你没有技术上的破坏同步,仅仅依靠StringBuffer来提供你的同步需求,你可能会发现轻微的行为怪异。例如,考虑未来的要求,也记录消息的时间:

public static void log(String s) { 
    Date d = new Date(); 
    buffer.append(d.toString() + " " + s); 
} 

如果有相当数量的并发调用这个方法,你可能会遇到线程A创建新Date实例,上下文切换到另一个线程完成整个方法,然后返回到线程A.这将使您的日志看起来好像它正在向后移动,这绝对是而不是你想要的。

第三,也是最重要的是,将方法定义为​​具有声明性值。它传达了这个方法在多线程上下文中的行为方式,以及你如何期待两个并发呼叫相互作用。在为他人设计的公用事业功能中,这是至关重要的。

0

因为StringBuffer是线程安全的,所以你不需要在它周围有另一个同步点(这是同步会做的)。

0

StringBuilder在java中不是线程安全的。所以你可以使用线程安全的StringBuffer

​​关键字可以以两种不同的方式使用。

同步方法:它使该方法是线程安全的。

public synchronized static void log (String log) { 
     buffer.append(log); 
} 

同步声明:使其与指定对象线程安全的。

public static void log(String log) { 
    synchronized (buffer) { 
     buffer.append(log); 
    } 
} 
2

以及如何对这种方法...

你两种方法同样线程安全的(或不!看线以下)。无论调用哪种方法,都会发生同样的情况:只有一个字符串将被添加到共享缓冲区中。


使用线程安全对象不会使程序变得线程安全。您可以自行决定“线程安全”的含义。

当有人告诉你某些是线程安全的时,他们所希望的是,调用类的方法的多个线程无法使它们中的任何一个以“错误”的方式行为。

“错误”是什么意思?这得看情况。当然,任何不同意班级文件的行为都是错误的。通常,任何与合理程序员所期望的不同的行为都可能被错误地称为错误。

在StringBuffer的情况下,这里是“线程安全”的意思是:这意味着,:

  • 你不会找到你的程序没有把缓存中的缓冲器什么。
  • 从缓冲区中找不到任何东西缺失您的程序放在那里。
  • 您不会发现两个不同字符串中的字符相互交错,最后,
  • 如果您可以证明字符串A是在追加字符串B之前追加的,那么字符串A将出现在字符串之前的输出中B.

你举的例子方法的调用都是线程安全仅凭每一个使一个线程安全的共享对象只是一个电话的事实。

如果您有例如几个共享对象不过,这时候的对象的单个线程安全可能加起来线程安全的整个算法。

+0

非常感谢。这澄清了我对线程安全的担忧。 – CMZS