第5章 定时器Timer
- 创建一个Timer就是启动一个新的线程。
第6章 章例模式与多线程
如何使单例模式遇到多线程是安全的、正确的。
1.立即加载/“饿汉模式”
//在类初始化时就创建了静态对象,不管以后使不使用都会占据一定内存
public class Singleton {
private Singleton(){}
private static final Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
2.延迟加载/"懒汉模式"
//在第一次使用时实例化对象 Double-Check-Lock
//相传在JDK1.5之前这个双重检查也是有问题的但之后修复了
public class Singleton {
private Singleton(){}
private static Singleton instance;
public static Singleton getInstance() {
if (instance == null)//避免加大块锁效率低
synchronized (Singleton.class) {
if (instance == null)//避免并发时的错误
instance = new Singleton();
}
return instance;
}
}
3.静态内部类实现单例
public class Singleton {
private Singleton(){}
/*
*1.此处要用到类中静态属性变量的特性:
* 静态变量属于类并非对象,在类加载时就初始化完毕且就一次
*2.因内部内类中的静态的属性,所以此内部类需声明成静态内部类(说明见下)
*3.静态内部类在第一次使用时完成加载(说明见下)
*/
private static class InnerSingleton {
private static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return InnerSingleton.instance;
}
}
对上述第二条的解释(来自互联网):java类加载顺序,首先加载类,执行static变量初始化,接下来执行对象的创建,如果我们要执行代码中的内部类静态变量的初始化,那么必须先执行加载外部类,再加载内部类,最后初始化内部类中的静态变量,问题就出在加载内部类上面,我们可以把内部类看成外部类的非静态成员,它的初始化必须在外部类对象创建以后进行,要加载内部类必须在实例化外部类之后完成,java虚拟机要求所有的静态变量必须在对象创建之前完成,这样便产生了矛盾。
对上述第三条的解释(来自互联网):静态内部类的加载不需要依附外部类,在使用时才加载。不过在加载静态内部类的过程中也会加载外部类。静态内部类和非静态内部类一样,都是在被调用时才会被加载。
4.静态代码块实现单例
//静态代码块中的代码在使用类的时候就已经执行了,所以可以应用这个特性来实现单例
public class Singleton {
private Singleton(){}
private static Singleton instance = null;
static {
instance = new Singleton();
}
public static Singleton getInstance() {
return instance;
}
}
5.枚举实现单例
//enum类型的值实际上是通过在运行期构造出对象来表示的
//可以说使用的时候其实就是个已经初始化好了的对象
public enum Singleton {
INSTANCE
}
上述前四种在序列化对象再通过反序列化得到对象时得到的结果还是多例的,解决办法如下:
//这就麻烦了,因为如果此单中如果有其它对象的话还得弄成transient的 protected Object readResolve() throws ObjectStreamException { return someInstance;//单例对象 }
但枚举类型单例不存在序列化这个问题
第7章 拾遗增补
- 线程状态:NEW,RUNNABLE,TERMINATED,TIMED_WAITING,BLOCKED,WAITING
myThread.getState();
- 线程组:可以指的管理线程或线程组对象,有效地对线程或线程组对象进行组织。
ThreadGroup group = new ThreadGroup("Group_Name");//线程组
Thread t1 = new Thread(group, new Thread(...));//管理线程
- 线程中出现异常的处理
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
publi void uncaughtException(Thread t, Throwable e) {
//some logic
e.printStackTrace();
}
}
t1.start();
}
- 方法
setUncaughtExceptionHandler()
是给指定线程对象设置的anip处理器。在Thread类中还可以使用setDefaultUncaughtExceptionHandler()
方法对所有线程对象设置异常处理器。
public static void main(String[] args) {
MyThread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandlert() {
@Override
public void uncaughtException(Thread t, Throwable e) {
//some logic
e.printStrackTrace();
}
}
MyThread t1 = new MyThread();
t1.start();
}
网友评论