java计时器

Posted jinshiyill

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java计时器相关的知识,希望对你有一定的参考价值。

一 Timer类与TimerTask类

      在Java中要实现定时执行某项任务就需要用到Timer类和TimerTask类。其中,Timer类可以实现在某一刻时间或某一段时间后安排某一个任务执行一次或定期重复执行,该功能需要与TimerTask类配合使用。TimerTask类表示由Timer类安排的一次或多次重复执行的那个任务。

      Timer类中的常用方法:

方法 描述
void cancel() 终止此计时器,丢弃所有当前已安排的任务,对当前正在执行的任务没有影响
int purge() 从此计时器的任务队列中移除所有已取消的任务,一般用来释放内存空间
void schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务
void schedule(TimerTask task, Date firstTime, long period) 安排指定的任务在指定的时间开始进行重复的固定延迟执行
void schedule(TimerTask task, long delay)  安排在指定延迟后执行指定的任务
void schedule(TimerTask task, long delay, long period) 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行
void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 安排指定的任务在指定的时间开始进行重复的固定速率执行
void scheduleAtFixedRate(TimerTask task, long delay, long period)  安排指定的任务在指定的延迟后开始进行重复的固定速率执行

注:1)上面提到的时间的单位都是毫秒

      2)schedule()方法和scheduleAtFixedRate()方法的区别在于重复执行任务时对于时间间隔出现延迟的情况的处理:schedule()方法的执行时间间隔永远是固定的,如果之前出现了延迟情况,那么之后也会继续按照设定好的时间间隔来执行;scheduleAtFixedRate()方法在出现延迟情况时,则将快速连续地出现两次或更多的执行,从而使后续执行能够“追赶上来”。从长远来看,执行的频率将正好是指定周期的倒数(假定 Object.wait(long) 所依靠的系统时钟是准确的)

二 一个定时任务范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package javase.timer;
 
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
 
class MyTask extends TimerTask{
    public void run() {
        Format format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        System.out.println("当前时间:" + format.format(new Date()));    
    }
     
}
 
public class Demo {
 
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new MyTask(), 1000100);  //1秒后执行,并且每隔100毫秒重复执行
         
        try {
            Thread.sleep(2000);
        catch (InterruptedException e) {
            e.printStackTrace();
        }
         
        timer.cancel();  //终止计时器,放弃所有已安排的任务
        timer.purge();  //释放内存
    }
 
}

输出:

1
2
3
4
5
6
7
8
9
当前时间:2016-03-01 15:02:36:451
当前时间:2016-03-01 15:02:36:477
当前时间:2016-03-01 15:02:36:578
当前时间:2016-03-01 15:02:36:678
当前时间:2016-03-01 15:02:36:778
当前时间:2016-03-01 15:02:36:878
当前时间:2016-03-01 15:02:36:978
当前时间:2016-03-01 15:02:37:078
当前时间:2016-03-01 15:02:37:178

 

      从上面的代码可以看出,操作步骤跟线程是差不多的,首先是用一个类实现TimerTask接口,然后在run()方法里定义具体的任务,最后通过一个Timer实例定时调用这个任务执行(PS:有些java教程里面是这样讲的,实际上TimerTask实现了runnable接口,因此就少了我们很多的操作)

三 使用Timer实现的新闻定时自动采集

      在这里,我选用的测试目标是“中国新闻网”的滚动新闻,链接是:http://www.chinanews.com/scroll-news/news1.html 。然后接下来的步骤就很明确了,设置定时任务定时去访问这个网页,然后每次访问时用正则表达式将我们需要的最新新闻的标题、URL、类型和时间提取出来,最后是保存到数据库中。完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package javase.timer;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
class CollectionTask extends TimerTask {
 
    public void run() {
        synchronized (this) {
            List<String[]> news = getCurrentNews();
            if (news.size() > 0)
                saveNews(news);
        }
 
    }
 
    /**
     * 获取最新的“中国新闻网”的滚动新闻
     
     * @return 最新滚动新闻的list列表
     * */
    private List<String[]> getCurrentNews() {
        List<String[]> newsList = new ArrayList<String[]>();
 
        try {
            URL url = new URL("http://www.chinanews.com/scroll-news/news1.html");
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000);
            connection.setReadTimeout(5000);
 
            if (connection.getResponseCode() == 200) {
                InputStream inputStream = url.openStream();
                // 注意编码问题,因为目标网页用的是gb2312,因此我这里也设置成gb2312,不然容易导致乱码
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(inputStream, "gb2312"));
                String line = "";
                Pattern pattern = Pattern
                        .compile("<li><div class=\"dd_lm\">\\[<a href=.*?>(.+?)</a>\\]</div>.*?<div class=\"dd_bt\"><a href=\"([^\"]+)\">(.+)?</a></div><div class=\"dd_time\">(.+)?</div></li>");
                Matcher matcher = null;
                while ((line = reader.readLine()) != null) {
                    // System.out.println(line);
                    matcher = pattern.matcher(line);
                    if (matcher.find()) {
                        String[] news = new String[4]; // 存储每条新闻的各个元素的数组
                        news[0] = matcher.group(1); // 类型
                        news[1] = matcher.group(2); // URL
                        news[2] = matcher.group(3); // 标题
                        news[3] = matcher.group(4); // 时间
 
                        newsList.add(news);
                    }
                }
                // for(int i=0;i<newsList.size();i++){
                // String[] temp = newsList.get(i);
                // System.out.println("分类:" + temp[0] + "  标题:" + temp[2] +
                // "  URL:" + temp[1] + "  时间:" + temp[3]);
                // }
                reader.close();
                inputStream.close();
                connection.disconnect();
                return newsList;
            }
 
        catch (MalformedURLException e) {
            e.printStackTrace();
        catch (IOException e) {
            e.printStackTrace();
        }
 
        return newsList;
    }
 
    /**
     * 保存新闻列表到数据库
     
     * @param news
     *            待保存的新闻列表
     * */
    private void saveNews(List<String[]> news) {
        Connection connection = JDBCDemo.getConnection(); // 获取数据库连接
        try {
            PreparedStatement pStatement = null;
 
            // 遍历,然后判断该条新闻是否已经在数据库中存在,不存在则保存
            for (String[] temp : news) {
                // System.out.println("分类:" + temp[0] + "  标题:" + temp[2] +
                // "  URL:"
                // + temp[1] + "  时间:" + temp[3]);
 
                pStatement = connection
                        .prepareStatement("select id from rollnews where url = ?");
                pStatement.setString(1, temp[1]);
                ResultSet resultSet = pStatement.executeQuery();
                if (resultSet.next())
                    continue;
                else {
                    pStatement = connection
                            .prepareStatement("insert into rollnews(title,url,type,time) values(?,?,?,?)");
                    pStatement.setString(1, temp[2]);
                    pStatement.setString(2, temp[1]);
                    pStatement.setString(3, temp[0]);
                    pStatement.setString(4, temp[3]);
 
                    pStatement.executeUpdate();
                }
 
            }
            pStatement.close();
            connection.close();
        catch (SQLException e) {
            e.printStackTrace();
        }
 
    }
 
}
 
public class NewsCollection {
 
    public static void main(String[] args) {
        Timer timer = new Timer();
        // timer.schedule(new CollectionTask(), 1000, 120000);
        timer.scheduleAtFixedRate(new CollectionTask(), 1000120000);
    }
 
}

附:

(1)JDBCDemo.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package javase.timer;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
 
public class JDBCDemo {
 
    public static Connection getConnection(){
        try {
            Class.forName("com.mysql.jdbc.Driver");
             
            return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/news?useUnicode=true&characterEncoding=utf-8""root""root");
        catch (ClassNotFoundException e) {
            e.printStackTrace();
        catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
 
}

(2)SQL结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
Navicat MySQL Data Transfer
 
Source Server         : sel
Source Server Version : 50519
Source Host           : localhost:3306
Source Database       : news
 
Target Server Type    : MYSQL
Target Server Version : 50519
File Encoding         : 65001
 
Date: 2016-03-01 15:35:06
*/
 
SET FOREIGN_KEY_CHECKS=0;
 
-- ----------------------------
以上是关于java计时器的主要内容,如果未能解决你的问题,请参考以下文章

自动刷新android片段,直到满足条件

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

测试片段不执行定时器或示例超时

如果用户没有使用浏览器,则jQuery计时器停止

颤振计时器仅更新秒小部件

java代码在片段活动中不起作用

(c)2006-2024 SYSTEM All Rights Reserved IT常识