跨多个线程访问一个字符串 [英] accessing a String across multiple threads
问题描述
我正在这里寻找一些输入.我有一个单例类,其中包含一个由该类中的方法每隔几秒钟更新一次的值.现在,跨线程访问此值是通过同步完成的,我想消除这一点.这有道理吗?
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屋!