假设我有一个单身人士:
public class MySinglton {
private static volatile MySinglton s;
private int x;
public static MySinglton getInstance() {
if (s != null) return s;
synchronized (MySinglton.class) {
if (s == null) {
s = new MySinglton();
}
}
return s;
}
public void setX(int x){
this.x = x;
}
}
好的,方法getInstance是线程安全的。我的问题是。是否有必要修改方法setX,或者它是线程安全的,因为getInsatnce方法是线程安全的。如果不是更好的话。
synchronized public void setX(int x){
this.x = x;
}
public void setX(int x){
synchronized (this) {
this.x = x;
}
}
或最后
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void setX(int x){
readWriteLock.readLock().lock();
this.x = x;
readWriteLock.readLock().unlock();
}
答案 0 :(得分:2)
仅仅因为getInstance()
是线程安全的,这并不意味着该类的任何其他方法都是线程安全的。多个线程仍然可以同时对单例对象执行操作。
您应该在setX
函数内同步私有的最终类成员对象。不同步this
并且不同步整个方法。同步this
同步对象,如果其他代码也同步getInstance()
返回的对象,您可能会陷入僵局。在方法之前放置synchronized关键字意味着在任何给定时间,实例上的线程只能执行类中同步方法的一个同步方法。它还可以给类的客户端/消费者留下印象,即该类是线程安全的,即使它可能不是。
编写单例的一个好方法是使用枚举,因为它保证只有一个实例。但是,如果您希望枚举的成员函数是线程安全的,那么它仍然需要同步。有关此示例,请参阅Effective Java的第311页:http://uet.vnu.edu.vn/~chauttm/e-books/java/Effective.Java.2nd.Edition.May.2008.3000th.Release.pdf
答案 1 :(得分:2)
没有setX不是线程安全的,因为可能有多个线程引用了singleton的实例,并且他们可能会尝试在同一个实例上执行setX
api。
您需要制作setX threadsafe。使用synchronized关键字的方法实现都可以。
我不会使用readWriteLock的read lock作为写入值。如果在你获得锁定和解锁之间发生了什么事情呢?你会解锁,从而导致死锁。所以总是在try / catch / finally块中使用锁定和解锁,在finally块中解锁。
答案 2 :(得分:1)
拥有单例并不能防止多个线程同时调用setX()。所以你肯定需要在这里同步。
在写入之前获取READ锁似乎很尴尬。要点是:读者(调用缺失的方法" getX()")需要一个readlock;在写作时,你想要一个WRITE锁!
准确地说:如果更新的属性不是"原子"那么你需要一个ReadWrite锁。和你的节目"知道"不同的读者"和#34;作家"作用。
如果只有" setX()"方法(没有读者,然后"同步"应该这样做;在这种情况下你不需要RW锁定。)
答案 3 :(得分:0)
在s的实例上调用setX。因此在JVM中任何给定时间只有一个s实例(bcos是单例)。如果两个线程同时调用setX,它们可以同时写入相同的x或相互踩踏。
setX不是隐式线程安全的。
这是一件好事
public void setX(int x){
synchronized (this) {
this.x = x;
}
}
以下是类似的帖子Java fine-grained synchronization in getter/setter methods and singleton pattern of a class
答案 4 :(得分:0)
public final class MySinglton
{
private final static MySinglton s;
private volatile int x;
static {
s = new MySinglton();
}
private MySinglton() {}
public static MySinglton getInstance()
{
return s;
}
public void setX(int x)
{
this.x = x;
}
}
如果您对Singleton没有任何其他要求,您可以使用它。提供一个默认构造函数以避免其他实例并将该类标记为final,因此没有人可以扩展它。 将初始化放在静态块中对大多数程序都可以正常工作。如果遇到问题,只需将其包装在静态内部类中。
答案 5 :(得分:0)
你向我们展示的只是一个带有方法setX(int x)
的单例对象。但是,除了设置其他类无法看到的私有变量之外,setX(x)方法不会执行任何操作。
您尚未向我们展示使用 x的任何代码。在你向我们展示如何使用x之前,“线程安全”意味着什么。
“线程安全”就是确保您的程序能够执行您希望它执行的操作,无论其线程的执行如何交错。你希望你的程序做什么?
有时我们会讨论“线程安全”类。例如,人们说java.util.concurrent.ArrayBlockingQueue
是“线程安全的”。但这只意味着程序中的线程无法将ArrayBlockingQueue
置于错误的内部状态。它 not 意味着队列将始终包含程序希望它包含的对象,或者按程序所需的顺序。使用“线程安全”对象构建程序不会使程序线程安全。
MySingleton课程中还有哪些其他方法?它应该如何使用?