JAVA 多线程(9):单例模式 与线程组
单例模式大家都知道,不用多说,就是只保持一个实例~
比如(饥饿模式/饿汉模式):
private static TestOne testOne = new TestOne(); private TestOne() { } public static TestOne getInstance(){ return testOne; }
延迟加载:
private static TestOne testOne = null; private TestOne() { } public static TestOne getInstance(){ if(testOne==null){ testOne = new TestOne(); } return testOne; }
下面针对懒汉模式与多线程的实例。
如果是在多线程的情况下,就有可能出现错误,比如:
private static TestOne testOne = null; private TestOne() { } public static TestOne getInstance() { if (testOne == null) { try { Thread.sleep(5000); testOne = new TestOne(); } catch (InterruptedException e) { e.printStackTrace(); } } return testOne; } public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { System.out.println(TestOne.getInstance().hashCode()); } }; Thread t = new Thread(runnable); Thread t2 = new Thread(runnable); t.start(); t2.start(); }
输出:
说明创建了2个对象实例。
那么就同步呗:synchronized
synchronized (TestOne.class) { if (testOne == null) { try { Thread.sleep(5000); testOne = new TestOne(); } catch (InterruptedException e) { e.printStackTrace(); } } }
输出:
提高效率:
if (testOne == null) { try { Thread.sleep(5000); synchronized (TestOne.class) { if (testOne == null) { testOne = new TestOne(); } } } catch (InterruptedException e) { e.printStackTrace(); } }
输出:
这样的话,就只是在创建实例的时候进行同步,并且在同步中判断,那能不能把第一层去掉,不能,原因在于,如果只是单纯创建实例可以,但是如果在创建实例之前有其他操作的话还是要加2层。
官方叫这种用法叫做DCL检查机制(双重检查锁)。
还有其他的方式比如上面说的创建静态实例对象立即加载,或者静态内部类也可以(但是如果是序列化对象就不行),还有枚举。其实我觉得DCL 就挺好不是么~
关于线程组:
线程太多了,所以有了组,线程组用来统一管理多个线程,并且线程组是树形结构,线程组中还可以有线程组。
实例如下:
public static void main(String[] args){ // 隐私的添加了导主线程中 ThreadGroup threadGroup = new ThreadGroup("线程组"); // 添加到线程组中 Thread t = new Thread(threadGroup, new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } },"子线程"); t.start(); System.out.println(threadGroup.activeCount()); System.out.println(threadGroup.getName()); }
输出:
线程组拷贝:
ThreadGroup[] threadGroups = new ThreadGroup[Thread.currentThread().getThreadGroup().activeCount()]; Thread.currentThread().getThreadGroup().enumerate(threadGroups);
成灰之前,抓紧时间做点事!!