1、说明:单例模式是最简单的设计模式之一,单例模式适合于一个类只有一个实例的情况。
2、要求:确保一个类只有一个实例被建立,并提供了一个对对象的全局访问指针 。
3、注意事项:如何正确构建线程安全的单例模式。
不正确的构建,示例代码加测试代码如下:
package org.com.jsoup; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPublicTest { public static ThreadPublicTest test ; private final String threadName; private ThreadPublicTest() { System.out.println("构建方法执行,当前执行线程名称为:" + Thread.currentThread().getName());
threadName = Thread.currentThread().getName(); } public String getThreadName() { return threadName; } public static ThreadPublicTest getThreadPublicTest() { if (test == null){ test = new ThreadPublicTest(); } return test; } /** * @param args测试代码 * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { // 开始时间 long beginTime = System.nanoTime(); final int theadMax = 10; final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax); // 创建一个线程池,限制为最多theadMax个线程 final ExecutorService exec = Executors.newFixedThreadPool(theadMax); // 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完 final CountDownLatch downLatch = new CountDownLatch(theadMax); for (int i = 0; i < theadMax; i++) { Runnable runable = new Runnable() { @Override public void run() { try { // 排队等待 cyclicBarrier.await(); ThreadPublicTest test = ThreadPublicTest .getThreadPublicTest(); System.out.println(String.format("对象名称:%s 线程名称:%s", test.getThreadName(),Thread.currentThread().getName())); } catch (Exception e) { // 处理异常 } finally { // 减少计数值 downLatch.countDown(); } } }; // 将任务放入线程池执行 exec.execute(runable); } downLatch.await();// 等待所有的并发访问完 exec.shutdown();// 关闭线程池 System.out.println("执行完毕:" + (System.nanoTime() - beginTime)); } }
上面的测试代码输出为:
构建方法执行,当前执行线程名称为:pool-1-thread-1
构建方法执行,当前执行线程名称为:pool-1-thread-10
对象名称:pool-1-thread-10 线程名称:pool-1-thread-4
对象名称:pool-1-thread-10 线程名称:pool-1-thread-10
对象名称:pool-1-thread-10 线程名称:pool-1-thread-2
对象名称:pool-1-thread-10 线程名称:pool-1-thread-8
对象名称:pool-1-thread-10 线程名称:pool-1-thread-6
对象名称:pool-1-thread-1 线程名称:pool-1-thread-1
对象名称:pool-1-thread-10 线程名称:pool-1-thread-5
对象名称:pool-1-thread-10 线程名称:pool-1-thread-3
对象名称:pool-1-thread-10 线程名称:pool-1-thread-7
对象名称:pool-1-thread-10 线程名称:pool-1-thread-9
执行完毕:57840462
package org.com.jsoup; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPublicTest { public static final ThreadPublicTest test = new ThreadPublicTest() ; private final String threadName; private ThreadPublicTest() { System.out.println("构建方法执行,当前执行线程名称为:" + Thread.currentThread().getName()); threadName = Thread.currentThread().getName(); } public String getThreadName() { return threadName; } public static ThreadPublicTest getThreadPublicTest() { return test; } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { // 开始时间 long beginTime = System.nanoTime(); final int theadMax = 10; final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax); // 创建一个线程池,限制为最多theadMax个线程 final ExecutorService exec = Executors.newFixedThreadPool(theadMax); // 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完 final CountDownLatch downLatch = new CountDownLatch(theadMax); for (int i = 0; i < theadMax; i++) { Runnable runable = new Runnable() { @Override public void run() { try { // 排队等待 cyclicBarrier.await(); ThreadPublicTest test = ThreadPublicTest .getThreadPublicTest(); System.out.println(String.format("对象名称:%s 线程名称:%s", test.getThreadName(),Thread.currentThread().getName())); } catch (Exception e) { // 处理异常 } finally { // 减少计数值 downLatch.countDown(); } } }; // 将任务放入线程池执行 exec.execute(runable); } downLatch.await();// 等待所有的并发访问完 exec.shutdown();// 关闭线程池 System.out.println("执行完毕:" + (System.nanoTime() - beginTime)); } }
执行完毕:51450575
可以看到构建方法只执行了一次,这种实现方法的好处是代码简洁,线程获取单例的方法执行效率高,缺点就是代码一加载就会执行对象初始化,所以上面我们看到构造方法是在主线程中执行的。
那么我们采用线程同步的方式来实现延迟初始化,以下是示例加测试代码:
package org.com.jsoup; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPublicTest { public static ThreadPublicTest test ; private final String threadName; private ThreadPublicTest() { System.out.println("构建方法执行,当前执行线程名称为:" + Thread.currentThread().getName()); threadName = Thread.currentThread().getName(); } public String getThreadName() { return threadName; } public static synchronized ThreadPublicTest getThreadPublicTest() { if (test == null){ test = new ThreadPublicTest() ; } return test; } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { // 开始时间 long beginTime = System.nanoTime(); final int theadMax = 10; final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax); // 创建一个线程池,限制为最多theadMax个线程 final ExecutorService exec = Executors.newFixedThreadPool(theadMax); // 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完 final CountDownLatch downLatch = new CountDownLatch(theadMax); for (int i = 0; i < theadMax; i++) { Runnable runable = new Runnable() { @Override public void run() { try { // 排队等待 cyclicBarrier.await(); ThreadPublicTest test = ThreadPublicTest .getThreadPublicTest(); System.out.println(String.format("对象名称:%s 线程名称:%s", test.getThreadName(),Thread.currentThread().getName())); } catch (Exception e) { // 处理异常 } finally { // 减少计数值 downLatch.countDown(); } } }; // 将任务放入线程池执行 exec.execute(runable); } downLatch.await();// 等待所有的并发访问完 exec.shutdown();// 关闭线程池 System.out.println("执行完毕:" + (System.nanoTime() - beginTime)); } }
看看测试的执行结果:
构建方法执行,当前执行线程名称为:pool-1-thread-10
对象名称:pool-1-thread-10 线程名称:pool-1-thread-5
对象名称:pool-1-thread-10 线程名称:pool-1-thread-1
对象名称:pool-1-thread-10 线程名称:pool-1-thread-10
对象名称:pool-1-thread-10 线程名称:pool-1-thread-4
对象名称:pool-1-thread-10 线程名称:pool-1-thread-7
对象名称:pool-1-thread-10 线程名称:pool-1-thread-6
对象名称:pool-1-thread-10 线程名称:pool-1-thread-3
对象名称:pool-1-thread-10 线程名称:pool-1-thread-8
对象名称:pool-1-thread-10 线程名称:pool-1-thread-9
对象名称:pool-1-thread-10 线程名称:pool-1-thread-2
执行完毕:44952622
package org.com.jsoup; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPublicTest { private static class InternalHalder{ //JVM会根据需要的时候才会初始化ThreadPublicTest public static final ThreadPublicTest test = new ThreadPublicTest(); } public static ThreadPublicTest test ; private final String threadName; private ThreadPublicTest() { System.out.println("构建方法执行,当前执行线程名称为:" + Thread.currentThread().getName()); threadName = Thread.currentThread().getName(); } public String getThreadName() { return threadName; } public static ThreadPublicTest getThreadPublicTest() { return InternalHalder.test; } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { // 开始时间 long beginTime = System.nanoTime(); final int theadMax = 10; final CyclicBarrier cyclicBarrier = new CyclicBarrier(theadMax); // 创建一个线程池,限制为最多theadMax个线程 final ExecutorService exec = Executors.newFixedThreadPool(theadMax); // 创建锁存器,设置为theadMax个,表示要等待theadMax个线程执行完 final CountDownLatch downLatch = new CountDownLatch(theadMax); for (int i = 0; i < theadMax; i++) { Runnable runable = new Runnable() { @Override public void run() { try { // 排队等待 cyclicBarrier.await(); ThreadPublicTest test = ThreadPublicTest .getThreadPublicTest(); System.out.println(String.format("对象名称:%s 线程名称:%s", test.getThreadName(),Thread.currentThread().getName())); } catch (Exception e) { // 处理异常 } finally { // 减少计数值 downLatch.countDown(); } } }; // 将任务放入线程池执行 exec.execute(runable); } downLatch.await();// 等待所有的并发访问完 exec.shutdown();// 关闭线程池 System.out.println("执行完毕:" + (System.nanoTime() - beginTime)); } }