提问者显然混淆了单例和多线程的概念,至少他这两个概念都没有弄明白。这其实是两个问题,第一,单例模式是如何使用的,有什么优势;第二,多线程如果竞争单例模式中的那个单例,会有什么问题。下面我一一回答。
1.单例是为了让某个类的对象在整个程序中最多只存在一个实例化的对象,这样做有很多好处,首先是提高性能,其次可以共享一些信息,最后对于编写代码也有适当的简化效果。
单例模式有很多中写法,仅凭我的印象,这里举一个最简单的例子,包括单例模式和它的使用:
public class SingletonTest {
public static void main(String[] args) {
Singleton someone = Singleton.getInstance();
System.out.println("someone get Singleton = " + someone);
Singleton anotherone = Singleton.getInstance();
System.out.println("another one get Singleton = " + anotherone);
if (someone.equals(anotherone)) {
System.out.println("they are the same one.");
}
}
}
class Singleton{
private static Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
可以看到上面的单例模式,保证了不同的地方需要时,仅仅实例化一个对象,这样仅节省性能,又能简化编程。
下面说第二个问题,如果多线程访问这个单例模式中的单例对象,会有什么问题?其实,这个问题几乎和单例无关,它可以这么问。如果多个线程同时访问一个对象,会有什么问题?回答是:每个线程都会得到这个对象的引用(除非你设定了一些互斥机制导致多个线程不能同时得到对象的引用),但是访问这个对象的方法时,如果这个方法是“可重入的”(或者叫线程安全的),那么多个线程可以同时调用;如果这个方法是“不可重入的”(或者叫线程不安全的),那么就必须采用多线程中的互斥技术(锁、synchronize)来保护这个方法不会被多个线程同时调用。
最简单的,如果你认为单例中的某个方法是“不可重入的”,那么就用互斥技术保护它,例如:
public class SingletonTest2 {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new MyTask());
service.execute(new MyTask());
service.execute(new MyTask());
service.shutdown();
}
private static class MyTask implements Runnable {
@Override
public void run() {
SynchronizedSingleton singleton = SynchronizedSingleton.getInstance();
System.out.println(Thread.currentThread()+" get the singleton.");
singleton.someFunc();
System.out.println(Thread.currentThread()+" is over.");
}
}
}
class SynchronizedSingleton{
private static SynchronizedSingleton instance = null;
public static synchronized SynchronizedSingleton getInstance() {
if (instance == null) {
instance = new SynchronizedSingleton();
}
return instance;
}
public synchronized void someFunc(){
for (int i = 0; i < 10; i++) {
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread()+ " invoke someFunc at "+i+" times" );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在上面的代码中,三个线程同时获取了SynchronizedSingleton的单例对象。但是在调用someFunc方法时,由于我将其设置 为一个synchronized 方法,因此三个线程只能顺序调用,而不能并发的调用它。
希望能帮到你。