/** * 懒汉式单例1 * 事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效 * 没有考虑线程安全问题,它是线程不安全的,并发环境下很可能出现多个Singleton1 实例 */ public class Singletion1 { //第一步先将构造方法私有化 private Singletion1(){} // 然后声明一个静态变量保存单例的引用 private static Singletion1 singletion1 = null; //通过提供一个静态方法来获得单例的引用 public static Singletion1 getInstance(){ if (singletion1==null){ singletion1 = new Singletion1(); } return singletion1; } }
/** *懒汉式单例.保证线程安全 * */ public class Singletion2 { private Singletion2() {} private static Singletion2 singleton2 = null; //为了保证多线程环境下正确访问,给方法加上同步锁synchronized //虽然线程安全了,但是每次都要同步,会影响性能 // public static synchronized Singletion2 getInstance(){ // if (singleton2==null){ // singleton2 = new Singletion2(); // } // return singleton2; // } //为了保证多线程环境下的另一种实现方式,双重锁检查 //做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗 public static Singletion2 getInstance(){ if (singleton2 ==null){ synchronized (Singletion2.class){ if (singleton2==null){ singleton2 = new Singletion2(); } } } return singleton2; } }
/** *线程安全问题 */ public class Singletion2Test { String name = null; private Singletion2Test(){} //volatile关键字来声明单例对象 //方便编写多线程程序和利于编译器进行优化 private static volatile Singletion2Test singletion2Test = null; public static Singletion2Test getInstance(){ if (singletion2Test == null){ synchronized (Singletion2Test.class){ if (singletion2Test == null){ singletion2Test = new Singletion2Test(); } } } return singletion2Test; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void printInfo(){ System.out.println(name); } public static void main(String[] args){ Singletion2Test instance = Singletion2Test.getInstance(); instance.setName("abc"); Singletion2Test instance2 = Singletion2Test.getInstance(); instance.setName("def"); instance.printInfo(); instance2.printInfo(); System.out.println(instance==instance2); } }
/** * 懒汉式 * Singleton4 类被装载了,INSTANCE不一定被初始化 *只有显示通过调用getInstance方法时,才会显示装载LazyHolder 类 * 既实现了线程安全,又避免了同步带来的性能影响 * 利用了classloader的机制来保证初始化instance时只有一个线程 */ public class Singletion3 { // 先声明一个静态内部类 private static class LazyHolder{ private static final Singletion3 INSTANCE = new Singletion3(); } private Singletion3(){} public static final Singletion3 getInstance(){ return LazyHolder.INSTANCE; } }
/** *饿汉式单例 * 在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的 */ public class Singletion4 { private Singletion4(){} //声明静态变量,在类实例化之前就初始化变量,将对象引用保存 private static final Singletion4 SINGLETION = new Singletion4(); public static Singletion4 getInstance(){ return SINGLETION; } }
/** * 饿汉式 * 枚举式单例 *不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象 */ public class Singletion5 { private Singletion5(){} public static Singletion5 getInstance(){ return Singletion.Instance.getInstance(); } private enum Singletion{ Instance; private Singletion5 singletion5; private Singletion(){ singletion5 = new Singletion5(); } public Singletion5 getInstance(){ return singletion5; } } public static void main(String[] args){ Singletion5 instance1 = Singletion5.getInstance(); Singletion5 instance2 = Singletion5.getInstance(); System.out.println(instance1==instance2); } }
import java.util.HashMap; import java.util.Map; /** *登记式单例 * 内部实现还是用的饿汉式单例,因为其中的static方法块,它的单例在类被装载的时候就被实例化了 * 维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回 */ public class Singletion6 { private static Map<String,Singletion6> map = new HashMap<>(); static { Singletion6 singletion6 = new Singletion6(); map.put(singletion6.getClass().getName(),singletion6); } protected Singletion6(){} public static Singletion6 getInstance(String name){ if (name==null){ name = Singletion6.class.getName(); } if (map.get(name)==null){ try { map.put(name, (Singletion6) Class.forName(name).newInstance()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return map.get(name); } }
import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.CountDownLatch; /** *CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行 * * 与CountDownLatch的第一次交互是主线程等待其他线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。 * * 其他N 个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象, * 他们已经完成了各自的任务。这种通知机制是通过 CountDownLatch.countDown()方法来完成的; * 每调用一次这个方法,在构造函数中初始化的count值就减1。所以当N个线程都调 用了这个方法,count的值等于0, * 然后主线程就能通过await()方法,恢复执行自己的任务。 */ public class Test { public static void main(String[] args){ CountDownLatch latch = new CountDownLatch(100); Set<Singletion3> synchronizedSet = Collections.synchronizedSet(new HashSet<>()); for (int a=0;a<100;a++){ new Thread(){ @Override public void run() { synchronizedSet.add(Singletion3.getInstance()); } }.start(); latch.countDown(); } try { latch.await();//等待所有线程全部完成,最终输出结果 System.out.println(synchronizedSet.size());//1 } catch (InterruptedException e) { e.printStackTrace(); } } }
原文:https://www.cnblogs.com/fly-book/p/10369046.html