java多线程机制计时器_java多线程定时器与单例模式

定时器与单例模式

本次更新的主要内容是多线程中的定时器Timer和单例模式,本来打算分两次更新的,这次就在一起更新了。这次更新完之后,多线程的基础理论知识系列就完结了,后续会发布Mysql的内部技术分析,多线程实战等内容,也会不定时的在每一期穿插更新一个算法或者编程技巧。

主要内容如下:

0351c01f37b2a3968ef897662fbb99fe.png

1 、定时器

在JDK中,Timer类主要负责计划任务的功能,也就是在执行定的时间开始执行某一个任务,Timer类的主要任务是设置计划任务,但封装任务的类却是TimerTask类(抽象类)。

1.1、方法schedule(TimerTask task,Date time)

该方法的作用是在指定的日期执行一次某一个任务。

样例如下:

public class MyTask extends TimerTask {

@Override

public void run() {

//执行代码

}

}

MyTask task = new MyTask();

Timer timer = new Timer();

timer.schedule(task,new Date());

timer线程启动后,会一直存在,并没有结束,不能设置为守护线程,会影响task的执行。

执行时间晚于当前时间。 到时间自动执行。

执行时间早于当前时间。 立即执行

Timer中有多个TimerTask任务及任务延时。 TimerTask是以队列的方式一个一个被顺序地执行,所以执行时间有可能和预期不一样,因为前面的任务有可能消耗过大,后面的任务的运行时间也被延后。被延后的任务,会在前一个任务结束后立即执行。

1.2、方法schedule(TimerTask task,Date first,long period)

该方法的作用是在指定的日期之后按指定的时间间隔,无线循环地执行某一任务。

执行时间晚于当前时间。 到时间自动执行。

执行时间早于当前时间。 立即执行

执行任务时间被延时。 任务的消耗时间大于period值,任务被无间隔的循环执行。

TimerTask类的cancel()方法。 该方法的作用是将自身从任务队列中进行删除。其他任务不受影响。

Timer类的cancel方法。 该方法的作用是将任务队列中的全部任务进行清除。且进程被摧毁。该方法并不一定总是生效的,失败的原因是没有争抢到queue锁。

1.3、方法schedule(TimerTask task,long delay)

该方法是以当前时间为参考,再次基础上延迟一定的毫秒数后执行一次TimerTask任务。

1.4、方法schedule(TimerTask task,long delay,long period)

该方法是以当前时间为参考,在此时间基础上,延迟指定的毫秒数,再以某一时间间隔无限次的执行某一任务。

1.5、方法scheduleAtFixedRate(TimerTask task,Date firstTime,long period)

方法schedule和scheduleAtFixedRate都会按顺序执行,所以不要考虑非线程安全的情况。主要区别在于有没有追赶性。

scheduleAtFixedRate方法具有追赶性,执行任务时间晚于计划时间,被卡掉的时间的任务,也会被执行。而schedule方法不会。

2、单例模式

2.1、饿汉模式

饿汉模式,在调用方法前,实例已经被创建了。

public class MyObject {

//立即加载方式

private static MyObject myObject = new MyObject();

private MyObject(){

}

public static MyObject getInstance() {

//立即加载

//缺点不能有其他实例

//get方法没有同步

return myObject;

}

}

2.2、懒汉模式

懒汉模式,在调用方法时才被创建。

public class MyObject {

//立即加载方式

private static MyObject myObject;

private MyObject(){

}

public static MyObject getInstance() {

if(myObject != null){

}else {

myObject = new MyObject();

}

return myObject;

}

}

该代码在多线程环境中,会出现多个实例的情况,非安全。

解决办法:

声明关键字synchronized,但执行效率非常低下。

public class MyObject {

//立即加载方式

private static MyObject myObject;

private MyObject(){

}

synchronized public static MyObject getInstance() {

try{

if(myObject != null){

}else {

myObject = new MyObject();

}

}catch(Exception e ){

e.printStackTrace();

}

return myObject;

}

}

同步代码块,同上。

使用DCL双检查机制。成功解决。

public class MyObject {

//立即加载方式

private volatile static MyObject myObject;

private MyObject(){

}

public static MyObject getInstance() {

try{

if(myObject != null){

}else {

synchronized(MyObject.class){

if(myObject == null){

myObject = new MyObject();

}

}

}

}catch(Exception e ){

e.printStackTrace();

}

return myObject;

}

}

2.3、静态内部类

public class MyObject {

//内部类

private static class MyObjectHandler {

private static MyObject myObject = new MyObject();

}

private MyObject(){}

public static MyObject getInstance() {

return MyObjectHandler.myObject;

}

}

2.4、序列化问题

静态内部类可以达到线程安全,但是不能解决序列化时多个实例的问题。

public class MyObject {

//内部类

private static class MyObjectHandler {

private static MyObject myObject = new MyObject();

}

private MyObject(){}

public static MyObject getInstance() {

return MyObjectHandler.myObject;

}

protected Object readResolve() throws ObjectStreamException {

return MyObjectHandler.myObject;

}

}

2.5、静态代码块

原理:静态代码块在使用类是已经执行了。

public class MyObject {

private static MyObject instance = null;

private MyObject(){}

static {

instance = new MyObject();

}

public static MyObject getInstance(){

return instance;

}

}

2.6、枚举类实现

原理:和静态代码块类似,在使用枚举类时,构造方法会自动调用。职责单一原则,应该隐藏枚举类。

public class MyObject {

public enum MyEnumSingleton {

connectionFactory;

private Connection connection;

private MyEnumSingleton() {

try{

....

}catch(){

}

}

public Connection getConnection(){

return connection;

}

}

public static Connection getConnection() {

return MyEnumSingleton.connectionFactory.getConnection();

}

}


版权声明:本文为weixin_36415206原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。