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));
}
}