The core of the singleton pattern is that there can only be one instance
So there’s nothing to say that constructors can’t be exposed, or anyone can create instance objects – directly private
The first is unremarkable
Initialize the object directly when the class is loaded
The advantages are obvious. First of all, it’s simple and doesn’t involve concurrency safety issues, because the class is only loaded once, and the instance is loaded when the class is loaded, whether you use it or not, that’s the disadvantage, but I think it doesn’t matter, the class always needs to be used otherwise why do you load it
public class Single01 {
private static final Single01 INSTANCE=new Single01();
/** * privatize */
private Single01(a){}
public static Single01 getInstance(a){
returnINSTANCE; }}Copy the code
It is also possible to use the static code block, which is loaded at initialization.
public class Single01 {
private static final Single01 INSTANCE;
static {
INSTANCE=new Single01();
}
/** * privatize */
private Single01(a){}
public static Single01 getInstance(a){
returnINSTANCE; }}Copy the code
In the second one I started to solve the problem and I didn’t want to load the class directly
Just reload when called….
public class Single02 {
private Single02(a){}
private static Single02 INSTANCE;
public static Single02 getINSTANCE(a) {
if (INSTANCE==null){
INSTANCE=new Single02();
return INSTANCE;
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i=0; i<100; i++){newThread(()->{ System.out.println(Single02.getINSTANCE().hashCode()); }).start(); }}}Copy the code
When I run the program, there seems to be nothing wrong with the structure because the thread is executing too fast
But it’s actually a big problem because threads can produce instances at the same time as if, and that’s a big problem, for example.
public class Single02 {
private Single02(a){}
private static Single02 INSTANCE;
public static Single02 getINSTANCE(a) {
if (INSTANCE==null) {try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
INSTANCE=new Single02();
return INSTANCE;
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i=0; i<100; i++){newThread(()->{ System.out.println(Single02.getINSTANCE().hashCode()); }).start(); }}}Copy the code
On the basis of the original, I continue to add sleep in order to allow more threads to come in, while the opportunity. The results of
There are few of the same ah, it is better to the first one, I prefer the first one.
But this could be improved by adding a lock
public synchronized static Single02 getINSTANCE(a) {
if (INSTANCE==null) {try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
INSTANCE=new Single02();
return INSTANCE;
}
return INSTANCE;
}
Copy the code
Add a lock and the result is the same
But it’s too inefficient. It’s too stretched. Try adding a lock to a block of code.
public static Single02 getINSTANCE(a) {
if (INSTANCE==null) {try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
synchronized (Single02.class){
INSTANCE=new Single02();
return INSTANCE;
// if (INSTANCE==null){
// INSTANCE=new Single02();
// return INSTANCE;
/ /}
}
// try {
// Thread.sleep(1000);
// }catch (Exception e){
// e.printStackTrace();
/ /}
}
return INSTANCE;
}
Copy the code
This code output is problematic because the lock is guaranteed to run at least once at a time, but our requirement is to create instance code only once, so we need to apply a second judgment, otherwise, the problem will still occur
Now add the quadratic judgment
public static Single02 getINSTANCE(a) {
if (INSTANCE==null) {try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
synchronized (Single02.class){
if (INSTANCE==null){
INSTANCE=new Single02();
returnINSTANCE; }}}return INSTANCE;
}
Copy the code
You might think that the first check is useless, but it’s actually useful. You can filter out most of the threads before you get the lock. One more thing to remember is that you need to use volatile to get INSTANCE out of order or you might compile your native code out of order.
There’s a better way to do it
Using inner classes is the perfect solution to lazy loading, because static inner classes use it when loading
public class Single03 {
private Single03(a){}
static class SingleHolder{
private static final Single03 INSTANCE=new Single03();
public static Single03 getInstance(a){
returnINSTANCE; }}Copy the code
Then perfect can do the first thing in the inner class.
There’s another way that’s a little more interesting
public enum Single04 {
INSTANCE
}
Copy the code
It’s private static final, and it can’t be deserialized, it can’t be reflected, because enumerations don’t have constructors, and it instantiates them for you