我正在写一个静态实用程序方法。我知道方法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

假设Thread1Thread2之前确实发生了(如输出所示),如果getTotal本来是thread-safe,则如果必须在输出中打印循环,则语句 Thread1在其中。但事实并非如此。 为什么? 因为在Thread1(带有sb =“1021”)进入getTotal方法后进入休眠状态,所以该线程被Thread2抢占了。 Thread222附加到现有StringBuilder对象sBuilder(即,新值现在是102122)。同样,当为Thread2调用sleep方法时,它会被Thread1抢占。 Thread1进入if构造,但是直到现在sBuilder的内容已更改为102122。因此,如果Thread1的条件变为假。如果我们认为Thread1 is within if loop是线程安全的,它不会打印我们期望的那一行getTotal。因此,它证明getTotal不是线程安全的。
我们如何使getTotal ThreadSafe?

10-04 22:57