【发布时间】:2020-02-07 12:24:58
【问题描述】:
package singleton;
public class SingletonClass {
private static SingletonClass singleton = null;
private SingletonClass() {
}
static boolean stopThread = true;
//approach 1 which fails in multithereaded env
/*public static SingletonClass getInstance(){
if(null == singleton){
try {
if(stopThread){
stopThread = false;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SingletonClass();
}
return singleton;
}*/
//approach 2 which works
//method is synchronized
/* public static synchronized SingletonClass getInstance(){
if(null == singleton){
try {
if(stopThread){
stopThread = false;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SingletonClass();
}
return singleton;
}*/
***//approach 3 which is failing but I don't understand why
//big block of code is synchronized
public static SingletonClass getInstance(){
if(null == singleton){
synchronized (SingletonClass.class){
try {
if(stopThread){
stopThread = false;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
singleton = new SingletonClass();
}
}
return singleton;
}***
//small block of code is synchronized, checked null again because even object instantiation is synchronised
//if we don't check null, it will create new object once again
//approach 4 which works
/* public static SingletonClass getInstance(){
if(null == singleton){
try {
if(stopThread){
System.out.println("in thread...");
stopThread = false;
//even if we interchange above 2 lines it makes whole lot of difference
//till the time it takes to print "in thread"
//2nd thread reaches there n enters if(stopThread) block because
//stopThread is still true because 1st thread spent time in writing that sentence and
//did not set stopThread = false by the time 2nd thread reached there
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (SingletonClass.class){
System.out.println("in this block");
if(null == singleton){
singleton = new SingletonClass();
}
}
}
return singleton;
}*/
}
---------------------------------------------------------
package singleton;
public class ThreadUsage implements Runnable {
@Override
public void run() {
SingletonClass singletonOne = SingletonClass.getInstance();
System.out.println(singletonOne.hashCode());
}
}
----------------------------------------------------------------
package singleton;
class ThreadUsageTest {
public static void main(String[] args) {
Runnable runnableOne = new ThreadUsage();
Runnable runnableTwo = new ThreadUsage();
new Thread(runnableOne).start();
new Thread(runnableTwo).start();
}
}
---------------------------------------------------------------------------
在方法 3 中,它没有为 2 个对象提供相同的 hashCode,我将 Thread.sleep 和对象实例化都保留在同步块下,所以我在想的是,第二个线程甚至不应该进入这个块直到第一个完成,但它仍在做并创建导致 diff hashCode 的第二个对象。我在这里发什么信息?有人可以在这里纠正我的理解吗?如果我检查 null b4 对象的创建,那么它会按预期工作,但是为什么我需要在这里再次检查 null,因为我的整个代码都在同步块下?
if(null == singleton)
singleton = new SingletonClass();
【问题讨论】:
-
您将获得两个实例,因为您在同步块之外检查 null。将检查放入内部或使整个方法同步。
-
使用双重锁定。
标签: java multithreading concurrency singleton