跨多个线程访问一个字符串 [英] accessing a String across multiple threads

查看:87
本文介绍了跨多个线程访问一个字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在这里寻找一些输入.我有一个单例类,其中包含一个由该类中的方法每隔几秒钟更新一次的值.现在,跨线程访问此值是通过同步完成的,我想消除这一点.这有道理吗?

I'm looking for some input here. I have a singleton class that contains a value which is updated every few seconds by a method within that class. Right now, access to this value across multiple threads is done via synchronization, which I would like to eliminate. Would this make sense?

class DataSegment {

    private MetricsUpdater metrics = new MetricsUpdater.getInstance();

    public String printValues() {
        StringBuilder sb = new StringBuilder();
        sb.append(value1);
        sb.append(morevalues);
        sb.append(metrics.myValue); // this is the value that's currently synchronized
        return sb.toString();
    }
}


class MetricsUpdater {

    private String myValueSynchronized;
    public String myValue;

    public static MetricsUpdater getInstance() {
        if (theInstance == null) {
            theInstance = new MetricsUpdater();
        }
        return theInstance;
    }

    // this runs on a timer but to keep it simple I'll just define the method...
    private void updateMetrics() {

        synchronized(myValue) {
            // also, to keep things simple, I've replaced all of the actual logic with a method called someMethodToUpdateMyValue()
            myValueSynchronized = someMethodToUpdateMyValue();
            myValue = myValueSynchronized;
        }
    }
}

可能有许多DataSegment实例都从myValue中读取,但是metrics类是单例的. myValue仅每5秒左右更新一次,并且仅允许MetricsUpdater对其进行写入.这有道理吗?

There can be many instances of DataSegment all reading from myValue, but the metrics class is a singleton. myValue only updates every 5 seconds or so and only MetricsUpdater is allowed to write to it. Does that make sense?

如果仅允许所有其他线程读取它,甚至需要完全同步吗?我为此进行了一系列的JUnit测试,创建了许多DataSegment类的实例,所有实例都打印出疯狂的值,而且我还没有看到任何并发问题.

Does it even need to be synchronized at all if all of the other threads are only allowed to read it? I've run a boatload of JUnit tests on this, creating many instances of the DataSegment class all printing values like crazy and I have yet to see any concurrency issues.

推荐答案

您的代码存在一些问题.

There are some problems with your code.

synchronized(myValue) {
    myValueSynchronized = someMethodToUpdateMyValue();
    myValue = myValueSynchronized;
    Thread.sleep(100); 
}

您的关键部分是错误的,因为正在锁定myValue .假设您在退出关键部分之前放置了Thread.sleep(100).然后,这意味着其他线程将锁定新的myValue实例,从而可以进入关键部分.如果它是一个时间线程,并且它的频率很高.然后,您可以更新旧版本,从而覆盖新版本. 无论如何,锁定这样的监视器是一个坏习惯.使用ReentrantLock或在String的某些最终引用上进行同步.

your critical section is wrong because are taking lock on myValue. Suppose you put a Thread.sleep(100) before exiting critical section. Then it means other thread will take a lock on new myValue instance and thus can enter the critical section. if its a time thread and if its frequency is very high. Then you can have stale updated overriding the new ones. Anyways its a bad Practice to acqurie lock on such monitors. Use ReentrantLock or synchronize on some final reference of String.

    public static MetricsUpdater getInstance() {
        if (theInstance == null) {
            theInstance = new MetricsUpdater();
        }
        return theInstance;
    }

您的Singleton代码已损坏.使用DCL(双重检查锁定,请参阅下面的解决方案"部分). 或使用私有静态MetricsUpdater theInstance = new MetricsUpdate();.后来更好了,

Your Singleton code is broken. Use DCL (Double Checked Locking see below in my solution sec). Or Use private static MetricsUpdater theInstance = new MetricsUpdate();. Latter is better,

 sb.append(metrics.myValue); 

以上代码应在同步上下文中调用或声明为易失性.更好

The above code should be called in a synchronized context or declared as volatile. Latter is better

class MetricsUpdater {

    private static volatile MetricsUpdater theInstance;
    public volatile String myValue;

    /**
     * DCL . Please avoid
     * Better use 
     * private static MetricsUpdater theInstance = new MetricsUpdate();
     */
    public static MetricsUpdater getInstance() {
        if (theInstance == null) {
            synchronized(MetricsUpdate.class) {
                 if(theInstance == null) {
                     theInstance = new MetricsUpdater();
                 }
            }
        }
        return theInstance;
    }

    // this runs on a timer but to keep it simple I'll just define the method...
    // if your someMethodToUpdateMyValue is thread safe
    private void updateMetrics() {
            myValue = someMethodToUpdateMyValue();
    }
}

解决方案2:假设someMethodToUpdateMyValue不是线程安全的

不需要同步是引用读/写是原子的 而且我们已经将myValue声明为volatile

Solution 2 : Assuming someMethodToUpdateMyValue is not Thread Safe

No need of synchronization is reference read/write is atomic and we have delared myValue as volatile

class MetricsUpdater {

 private static volatile MetricsUpdater theInstance;
 public volatile String myValue;

 /**
 ** Use ReentrantLock instead
 */
 private final  Object lock  = new Object();


     /**
     * DCL . Please avoid
     * Better use 
     * private static MetricsUpdater theInstance = new MetricsUpdate();
     */
    public static MetricsUpdater getInstance() {
        if (theInstance == null) {
            synchronized(MetricsUpdate.class) {
                 if(theInstance == null) {
                     theInstance = new MetricsUpdater();
                 }
            }
        }
        return theInstance;
    }

// this runs on a timer but to keep it simple I'll just define the method...
private void updateMetrics() {
    synchronized(lock) {
        myValue = someMethodToUpdateMyValue();
    }
}

}

这篇关于跨多个线程访问一个字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆