上一篇已经解决了多线程下安全问题,但是程序运行速度也大大拖慢了,主要是getInstance方法在获取单例的时候存在耗时操作,导致很多线程堵在那里。
在真实的情况下,可能耗时操作这块业务是并不需要保证加锁的,而且有时候是不需要执行耗时操作的,我们将程序修改如下:
/**
* Mysql数据库连接池
*/
public class MysqlPool {
/**
* 保存单例的静态变量
*/
private static MysqlPool instance = null;
/**
* 使用private修饰构造函数,防止使用new方法产生实例,保证只能从getInstance生产实例
*/
private MysqlPool() {
// 此处可以一次性建立10个数据库连接,然后放到数组/list里面
}
/**
* 通过该方法获取单例
*/
public static MysqlPool getInstance() {// 此处测试时分别有synchronized和无synchronized
if (instance == null) {//规避不必要的耗时操作
try {
// 模拟耗时操作
Thread.sleep(50);
} catch (Exception ex) {
}
synchronized(MysqlPool.class) {//仅对必须要保护的代码加锁
if (instance == null) {
instance = new MysqlPool();
}
}
}
return instance;
}
}
对上面的代码进行速度测试,发现时间回归正常水平。
/**
* 用于测试单例的线程
*/
public class SingletonTestThread extends Thread {
private static long start = 0;
@Override
public void run() {
MysqlPool pool = null;
pool = MysqlPool.getInstance();
System.out.println(System.currentTimeMillis() - start);
}
/**
* 测试入口
*/
public static void main(String[] args) {
start = System.currentTimeMillis();
for (int i = 0; i < 100; i++) {
Thread thread1 = new SingletonTestThread();
thread1.start();
}
}
}
可见实际上具体问题是要具体分析的,灵活的运用synchronized加锁才能取得安全和效率上的平衡。