4

我是 Java 的新手,过去我没有使用过线程。现在,我的知识水平遇到了一个非常棘手的问题。

我开发了“发送邮件”和“检查邮件”两个功能。每个用户注册他的偏好,系统创建两个目录,其中包含许多用于定期工作的指令,例如

A) 每 1500 毫秒发送一次消息

B) 每 1800 毫秒发送一次消息

C) 每 3000 毫秒发送一次消息

A) 每 2000 毫秒检查一次消息

B) 每 6000 毫秒检查一次消息

C) 每 8000 毫秒检查一次消息

我用线程尝试了很多方法,但我没能做到。我的问题是同步它们的最佳方式是什么?下面是我最后一次使用线程的代码。

public class MailCreatorThread extends Thread {
    @Override
    public void run() {
        CreateMail(_date); //creates a mail with _date as subject
    }
}

public class GPSThread extends Thread {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (!_isTimeToStop) {
            try {
                while (_servicesToUpdate.size() == 0) {
                    Thread.sleep(500);
                }
                _currentService = (MyService) _servicesToUpdate.get(0)
                        .clone();
                _servicesToUpdate.remove(0);

                        MailCreatorThread mailCreatorThread = new MailCreatorThread();
                        mailCreatorThread.start();


            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

public class CheckServicesThread extends Thread {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (!_isTimeToStop) {
            try {
                Thread.sleep(1000);
                    for (int j = 0; j < _servicesList.length; j++) {
                        MyService currentService = ((MyService) _servicesList[j]);
                        if (myService.getTimeToNextUpdate() - 1000 <= 0) {
                            _servicesToUpdate
                                    .add((MyService) currentService
                                            .clone());
                            currentService
                                    .setTimeToNextUpdate(currentService
                                            .getUpdatePeriod());
                        } else {
                            currentService
                                    .setTimeToNextUpdate(currentService
                                            .getTimeToNextUpdate() - 1000);
                        }
                }

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        stopSelf();
    }
}
4

2 回答 2

4

您可以使用 aScheduledExecutorService来运行这些定期任务。语法相当简单:

Runnable check = new Runnable() {
    public void run() {
        checkMessage();
    }
}
Runnable send = new Runnable() {
    public void run() {
        sendMessage();
    }
}

//since what you are doing is mostly I/O you probably want to have 
//more than one thread available so that if one operation blocks,
//the other ones can be launched in parallel

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(10);
scheduler.scheduleAtFixedRate(check, 0, 1500, MILLISECONDS);
scheduler.scheduleAtFixedRate(send, 0, 6000, MILLISECONDS);

注意:不应再使用Ozzy 的答案Timer中提到的,因为它已在 Java 1.5 中由 改进,如Timer 的 javadoc中所述:ScheduledThreadPoolExecutor

Java 5.0 引入了 java.util.concurrent 包,其中的并发实用程序之一是 ScheduledThreadPoolExecutor,它是一个线程池,用于以给定的速率或延迟重复执行任务。它实际上是 Timer/TimerTask 组合的更通用替代品,因为它允许多个服务线程,接受各种时间单位,并且不需要子类化 TimerTask(只需实现 Runnable)。使用一个线程配置 ScheduledThreadPoolExecutor 使其等效于 Timer。

于 2012-04-17T18:58:36.450 回答
3

在 java 中,你有内置的 Timer 和 TimerTask 类来帮助你在一个单独的线程中重复一个任务。

这将创建一个 Timer,它将创建自己的后台线程:

Timer t = new Timer();

然后,您可以为该计时器安排任意数量的任务,它们将共享计时器自己的线程。

在 2000 毫秒 = 2 秒的延迟之后,您可以通过以下方式在计时器线程上安排单个任务:

t.schedule(new TimerTask() {
    @Override
    public void run() {
        //task to perform
    }
}, 2000);

这是您如何在计时器线程上安排重复任务,延迟 1 秒后,并以 1.5 秒的间隔重复任务:

t.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        //task to perform every 1.5 seconds
    }
}, 1000, 1500);

现在您可以选择将两个任务(checkMail、sendMail)安排到同一个 Timer(同一个线程)或给它们各自的 Timer(单独的线程)。

有关详细信息,请参阅 java 文档 (http://docs.oracle.com/javase/6/docs/api/java/util/Timer.html)

希望这可以帮助。

于 2012-04-17T17:42:45.860 回答