并发编程中的设计模式-单例模式
1.饿汉模式:在类加载的时候就创建对象,对系统的开销较大,但是不存在线程的安全问题;
1 class Singleton1 { 2 private static Singleton1 singleton = new Singleton1(); // 建立对象 3 private Singleton1() { 4 try { 5 Thread.sleep(1000); 6 System.out.println("构建这个对象可能耗时很长..."); 7 } catch (InterruptedException e) { 8 e.printStackTrace(); 9 } 10 } 11 public static Singleton1 getInstance() { 12 return singleton;// 直接返回单例对象 13 } 14 @Override 15 public String toString() { 16 return ""+this.hashCode(); 17 } 18 } 19 20 public class DemoThread22 { 21 public static void main(String[] args) throws InterruptedException { 22 23 ExecutorService es = Executors.newFixedThreadPool(10); 24 25 for(int i=0;i<10;i++){ 26 es.execute(new Runnable() { 27 @Override 28 public void run() { 29 Singleton1 instance = Singleton1.getInstance(); 30 System.out.println(instance); 31 } 32 }); 33 } 34 35 es.shutdown(); 36 } 37 }
2.懒汉模式一:懒汉模式在需要对象的时候才进行对象的创建,
1 class Singleton2 { 2 private static Singleton2 singleton = null; // 不建立对象 3 private Singleton2() { 4 } 5 /*synchronized 可以解决线程安全问题,但是存在性能问题,即使singleton!=null也需要先获得锁*/ 6 public synchronized static Singleton2 getInstance() { 7 if (singleton == null) { // 先判断是否为空 8 try { 9 Thread.sleep(1000); 10 System.out.println("构建这个对象可能耗时很长..."); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 singleton = new Singleton2(); // 懒汉式做法 15 } 16 return singleton; 17 } 18 19 @Override 20 public String toString() { 21 return ""+this.hashCode(); 22 } 23 } 24 public class DemoThread23 { 25 public static void main(String[] args) throws InterruptedException { 26 27 ExecutorService es = Executors.newFixedThreadPool(100); 28 29 for (int i = 0; i < 100; i++) { 30 es.execute(new Runnable() { 31 @Override 32 public void run() { 33 System.out.println(Singleton2.getInstance()); 34 } 35 }); 36 } 37 38 es.shutdown(); 39 } 40 }
3.懒汉模式性能安全的性能优化:上述的懒汉模式虽然是线程安全的,但是线程每次在调用getInstance()方法的时候都会对这个方法进行上锁,其实这样是没有必要的,因为当对象被创建之后就不需要对该方法上锁了,所以进行了如下优化。只有在第一次创建对象时上锁。
1 class Singleton3 { 2 private static Singleton3 singleton = null; // 不建立对象 3 private Singleton3() { 4 } 5 /*synchronized 代码块进行双重检查,可以提高性能*/ 6 public static Singleton3 getInstance() { 7 if (singleton == null) { // 先判断是否为空 8 synchronized (Singleton3.class) { 9 //此处必须进行双重判断,否则依然存在线程安全问题 10 if(singleton == null){ 11 try { 12 Thread.sleep(1000); 13 System.out.println("构建这个对象可能耗时很长..."); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 singleton = new Singleton3(); // 懒汉式做法 18 } 19 } 20 } 21 return singleton; 22 } 23 24 @Override 25 public String toString() { 26 return ""+this.hashCode(); 27 } 28 } 29 public class DemoThread24 { 30 public static void main(String[] args) throws InterruptedException { 31 32 ExecutorService es = Executors.newFixedThreadPool(100); 33 34 for (int i = 0; i < 10; i++) { 35 es.execute(new Runnable() { 36 @Override 37 public void run() { 38 System.out.println(Singleton3.getInstance()); 39 } 40 }); 41 } 42 43 es.shutdown(); 44 } 45 }
4.静态内部类的单例模式:也是只会在第一次需要的时候创建对象,以后每次获取该对象的时候后都不会再次创建对象,线程是安全的。
1 class Singleton4 { 2 private static class InnerSingletion { 3 private static Singleton4 single = new Singleton4(); 4 } 5 6 private Singleton4(){ 7 try { 8 Thread.sleep(1000); 9 System.out.println("构建这个对象可能耗时很长..."); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 } 14 15 public static Singleton4 getInstance(){ 16 return InnerSingletion.single; 17 } 18 19 @Override 20 public String toString() { 21 return ""+this.hashCode(); 22 } 23 } 24 25 public class DemoThread25 { 26 public static void main(String[] args) throws InterruptedException { 27 ExecutorService es = Executors.newFixedThreadPool(100); 28 for (int i = 0; i < 10; i++) { 29 es.execute(new Runnable() { 30 @Override 31 public void run() { 32 System.out.println(Singleton4.getInstance()); 33 } 34 }); 35 } 36 37 es.shutdown(); 38 } 39 }