我正在写一个静态实用程序方法。我知道方法isEmpty()
和isNew()
是线程安全的。在getTotal(...)
方法中,我将StringBuilder
与String和int一起用作参数。 StringBuilder
是可变的。 getTotal()
线程安全吗?如果是这样,则说明即使StringBuilder是可变的也是如此。我不确定getCharge()
是否是线程安全的,因为它正在调用getTotal()
方法。有人可以说出它是否是线程安全的吗?
public class NewStringUtils {
public static boolean isEmpty(String s){
return (s == null || s.trim().length()==0);
}
public static boolean isNew(String code){
return( "1009".equals(code) || "1008".equals(code) );
}
//StringBuilder is mutable -- is the below method threadsafe
public static int getTotal(StringBuilder sb,String oldCode ,int a, int b){
//Is it Threadsafe or not .If so just bcz every thread invoking this method will have its own copy and other threads can't see its value ??
int k =0;
if("1011".equals(oldCode) && "1021".equals(sb.toString()) {
k = a+b;
}
return k;
}
// is the below method threadsafe
public static int getCharge(String code,String oldCode,int charge1,int charge2){
int total =0;
StringBuilder sb = new StringBuilder("1021");
if(!NewStringUtils.isEmpty(code)){
if(NewStringUtils.isNew(code)){
//here invoking a static method which has StringBuilder(Mutable) as a parameter
total = NewStringUtils.getTotal(sb,oldCode,charge1,charge2);
}
}
return total;
}
}
最佳答案
getTotal
不是thread-safe
,因为有可能两个或两个以上的threads
将相同的StringBuilder
引用作为争论传递给getTotal
方法,并在传递之前修改了StringBuilder
...
您的getCharge
完全是线程安全的,因为在这里,每个thread
都在自己的StringBuilder
中制作stack
Object的本地副本。因此,不必担心getCharge
的线程安全性。
这是简短的演示,演示了getTotal
不是ThreadSafe的原因:
class ThreadSafe
{
public static int getTotal(StringBuilder sb,String oldCode ,int a, int b)
{
int k =0;
try
{
System.out.println(Thread.currentThread().getName() + " have sb as " + sb);
Thread.sleep(100);//Added intentionally to show why it is not thread safe.
}
catch (Exception ex)
{
System.out.println(ex);
}
if("1011".equals(oldCode) && "1021".equals(sb.toString()))
{
System.out.println(Thread.currentThread().getName()+" is within if loop");//Thread1 should be within this if block but it's not.
k = a+b;
}
return k;
}
public static void main(String[] args)
{
final StringBuilder sBuilder = new StringBuilder();
Thread th1 = new Thread(new Runnable()
{
public void run()
{
sBuilder.append("1021");
getTotal(sBuilder,"1011",10,20);
}
},"Thread1");
Thread th2 = new Thread(new Runnable()
{
public void run()
{
sBuilder.append("22");
getTotal(sBuilder,"1011",10,20);
}
},"Thread2");
th1.start();
th2.start();
}
}
在我的系统上,输出为:
Thread1 have sb as 1021
Thread2 have sb as 102122
假设
Thread1
在Thread2
之前确实发生了(如输出所示),如果getTotal
本来是thread-safe
,则如果必须在输出中打印循环,则语句 Thread1在其中。但事实并非如此。 为什么? 因为在Thread1
(带有sb =“1021”)进入getTotal
方法后进入休眠状态,所以该线程被Thread2
抢占了。 Thread2
将22
附加到现有StringBuilder
对象sBuilder
(即,新值现在是102122
)。同样,当为Thread2
调用sleep方法时,它会被Thread1
抢占。 Thread1
进入if
构造,但是直到现在sBuilder
的内容已更改为102122
。因此,如果Thread1
的条件变为假。如果我们认为Thread1 is within if loop
是线程安全的,它不会打印我们期望的那一行getTotal
。因此,它证明getTotal
不是线程安全的。我们如何使
getTotal
ThreadSafe?