java多线程定时任务的任务执行问题。

java多线程任务一般开多少个线程_百度知道
java多线程任务一般开多少个线程
我有更好的答案
  工程与科学方面的应用程序通常运行于专用的系统(可能没有多任务化)。而一个多线程NI LabVIEW程序可以被分解成四个线程,一个同步调用可能会阻止或防止该应用中的其他任务执行。该程序的执行可以持续地推进,这些仪器调用时常需要较长的时间完成:用户界面、数据采集,如仪器。  利用多线程的应用具有以下几大优势:1更有效的CPU利用率2更好的系统可靠性3改善多处理器计算机的性能  在许多应用中,您同步地调用资源,因此,您可以将单个应用中的特定步骤进一步分解成一个个线程,每个线程可以并行运行,多项任务可以与该系统执行的其他应用并行执行,而不是停滞直到完成同步调用,以便它们独立工作。于是,在多线程应用中。而多线程避免了这样的情况出现。  当同步调用在一个线程中运行时。在一个单线程应用中。  多线程将多任务的思想拓展到应用,多个任务需要多线程处理 一个线程是只能执行一个任务、网络通信以及数据录入。您可以分别赋予这四个线程的优先级,程序中不依赖于该调用的其它部分可以在其它线程中运行。操作系统不仅在不同的应用任务间分配处理时间,而且在一项应用的每个线程间分配处理时间,直至该操作完成
【0元入学,两周免费试听】
主营:培训【Python+人工智能,Java大数据,HTML5】
为您推荐:
其他类似问题
您可能关注的内容
线程的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。博客分类:
java线程和线程池
一、创建多线程的方式
java多线程很常见,如何使用多线程,如何创建线程,java中有两种方式,第一种是让自己的类实现Runnable接口,第二种是让自己的类继承Thread类。其实Thread类自己也是实现了Runnable接口。具体使用实例如下:
1、通过实现Runnable接口方式
public class MyThread1 implements Runnable
String sign = "thread#1@";
public void run()
for (int i = 0; i & 30; i++)
System.out.println(sign + "-&" + i);
Thread.sleep(100L);
} catch (InterruptedException e)
e.printStackTrace();
2、通过继承Thread类的方式
public class MyThread2 extends Thread
String sign = "thread#2@";
public void run()
for (int i = 0; i & 30; i++)
System.out.println(sign + "-&" + i);
Thread.sleep(100L);
} catch (InterruptedException e)
e.printStackTrace();
再启用上面创建的两种线程,调运代码如下:
public static void main(String[] args) throws InterruptedException
long startTime = System.currentTimeMillis();
Runnable myThread1 = new MyThread1();
Thread thread1 = new Thread(myThread1);
thread1.start();
Thread thread2 = new Thread(new MyThread2());
thread2.start();
Thread.sleep(1000L);
System.out.println("主线程结束!用时:"
+ (System.currentTimeMillis() - startTime));
输入结果(每次输入可能不同)不再详细列出。对于上面的两种方式,更推荐使用实现Runnable接口的方式实现多线程。一方面是可以防止java单继承的顾虑,另一方面Runnable是面向接口编程,扩展性比起继承Thread更好。所以尽量使用implement Runnable的方式。
二、java线程类型说明
上面是将多线程跑起来了,但是有个问题,如果不让主线程睡眠,当主线程(比如main线程)结束以后,如果子线程还没结束,那么子线程是否还会执行呢?答案是会继续执行,为了说明这个问题,就又涉及到java中线程的类型。java中线程一共有两种类型:守护线程(daemon thread)和用户线程(user thread)又叫非守护线程。可以通过thread.setDaemon()方法设置线程是否为守护线程,默认是设置非守护线程(false)。java虚拟机停止运行的时间是虚拟机中运行的所有线程都是守护线程的时候,也就是说如果jvm中没有user thread的时候,jvm就停止运行。或者说jvm在最后一个非守护线程结束的时候,将停止所有的守护进程,然后退出jvm。
当使用main方法开启线程时,主线程默认是非守护进程,而用户自己开的进程也是非守护进程。当主线程结束,但是子线程(默认是非守护线程)还没结束,所以虚拟机是不停止运行的,当子线程运行完以后,如果主线程也运行完毕,jvm发现没有非守护线程,就将jvm关闭,所以当main方法的主线程执行完毕以后,子线程是会继续执行的。当然我们也可以让在main主线程执行完毕以后,子线程不再执行,方法就是将所有的子线程设置为守护进程setDaemon(true)即可。但是需要注意的是这个设置需要在线程运行之前设置,不能在线程运行的过程中修改线程类型。
更直白点说如果用户将线程设置为守护进程,那实际的意思就是告诉jvm你不用搭理我这个线程,jvm想停止的时候,不用考虑我这个线程是否执行结束。这种线程具体的使用比如在垃圾回收机制的线程,就是一个守护线程。
Runnable myThread1 = new MyThread1();
Thread thread1 = new Thread(myThread1);
thread1.setDaemon(true);
thread1.start();
Thread thread2 = new Thread(new MyThread2());
thread2.setDaemon(false);
thread2.start();
System.out.println("mainThread isDaemon:"
+ Thread.currentThread().isDaemon());
System.out.println("thread1 isDaemon:" + thread1.isDaemon());
System.out.println("thread2 isDaemon:" + thread2.isDaemon());
三、线程池的使用
上面已经看过了可以在代码中直接新起线程,如果我们在主线程中新起一百个线程,让这一百个线程同时工作,逻辑上是没有任何问题的,但是这样做对系统资源的开销很大,这样会在短时间内处理很多的任务,当然包括新起线程等等。基于这样的考虑,我们是有必要引入线程池这个东西的。线程池就是一个池子,池子里有很多可用线程资源,如果需要就直接从这个池子里拿就是。当不用的时候,放入池子中,线程池会自动帮我们管理。所以使用线程池主要有以下两个好处:1、减少在创建和销毁线程上所花的时间以及系统资源的开销 2、如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存 。
如果我们想要使用线程池,就需要先定义这个线程池。定义线程池的时候,其中的几个主要参数说明如下:-corePoolSize(int):线程池中保持的线程数量,包括空闲线程在内。也就是线程池释放的最小线程数量界限。
-maximumPoolSize(int):线程池中嫩容纳最大线程数量。
-keepAliveTime(long):空闲线程保持在线程池中的时间,当线程池中线程数量大于corePoolSize的时候。
-unit(TimeUnit枚举类):上面参数时间的单位,可以是分钟,秒,毫秒等等。
-workQueue(BlockingQueue&Runnable&):任务队列,当线程任务提交到线程池以后,首先放入队列中,然后线程池按照该任务队列依次执行相应的任务。可以使用的workQueue有很多,比如:LinkedBlockingQueue等等。
-threadFactory(ThreadFactory类):新线程产生工厂类。
-handler(RejectedExecutionHandler类):当提交线程拒绝执行、异常的时候,处理异常的类。该类取值如下:(注意都是内部类)
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务,重复此过程。
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。
除了自定义线程池以外, java提供了几种常用的线程池,可以快捷的供程序员使用,他们分别是:
1、newFixedThreadPool 创建固定大小数量线程池,数量通过传入的参数决定。
2、newSingleThreadExecutor 创建一个线程容量的线程池,所有的线程依次执行,相当于创建固定数量为1的线程池。
3、newCachedThreadPool 创建可缓存的线程池,没有最大线程限制(实际上是Integer.MAX_VALUE)。如果用空闲线程等待时间超过一分钟,就关闭该线程。
4、newScheduledThreadPool 创建计划(延迟)任务线程池,线程池中的线程可以让其在特定的延迟时间之后执行,也可以以固定的时间重复执行(周期性执行)。相当于以前的Timer类的使用。5、newSingleThreadScheduledExecutor 创建单线程池延迟任务,创建一个线程容量的计划任务。
其实通过静态方法创建的上面几种线程池,也都是通过传入默认的各个参数,然后返回一个有各自特点的线程池。具体参数可以通过查看jdk源码阅读。
有了线程池,那么我们如何利用线程池中线程执行我们的任务,由于Java将线程池的封装,我们拿到的线程池的线程其实是一个包含线程任务的执行器,只需要调运执行器的执行方法,就会自动执行我们线程中的任务。对于非计划任务,我们需要拿到一个ThreadPoolExecutor,对于计划任务,我们需要拿到一个ScheduledThreadPoolExecutor(它是ThreadPoolExecutor的子类)。在了解这两个类之前,需要先了解两个接口,ExecutorService以及它的子接口ScheduleThreadExecutorService接口,上面两个接口分别实现了这两个接口,这个两接口定义了execute(Runnable r)方法,这个方法去执行线程的任务。也就是我们通过调运ThreadPoolExecutor或者ScheduledThreadPoolExecutor的execute(Runnable r)方法开启我们的线程,并且执行我们的线程任务,具体代码如下:
定义一个单例的线程池:
public class MyPool
private static MyPool myPool = null;
private ThreadPoolExecutor threadPool = null;
private ScheduledThreadPoolExecutor scheduledPool = null;
public ThreadPoolExecutor getThreadPool()
return threadP
public ScheduledThreadPoolExecutor getScheduledPool()
return scheduledP
private int corePoolSize = 10;
private int maximumPoolSize = 20;
private long keepAliveTime = 3;
private int scheduledPoolSize = 10;
private static synchronized void create()
if (myPool == null)
myPool = new MyPool();
public static MyPool getInstance()
if (myPool == null)
return myP
private MyPool()
this.threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, TimeUnit.SECONDS,
new LinkedBlockingQueue&Runnable&(),
new ThreadPoolExecutor.DiscardOldestPolicy());
this.scheduledPool = new ScheduledThreadPoolExecutor(scheduledPoolSize);
获取线程池中的线程,并且执行线程中任务:
public void testThreadPool()
ThreadPoolExecutor pool1 = (ThreadPoolExecutor) Executors
.newCachedThreadPool();
pool1.execute(new Runnable()
public void run()
System.out.println("快捷线程池中的线程!");
ThreadPoolExecutor pool2 = MyPool.getInstance().getThreadPool();
pool2.execute(new Runnable()
public void run()
System.out.println("普通线程池中的线程");
ScheduledThreadPoolExecutor pool3 = MyPool.getInstance()
.getScheduledPool();
pool3.scheduleAtFixedRate(new Runnable()
public void run()
System.out.println("计划任务线程池中的线程");
}, 0, 1000, TimeUnit.MILLISECONDS);
四、计划任务执行使用
通过上面的例子,也看到了计划任务线程池的使用方式。对于计划任务,除了可以执行普不同线程池中线程的任务以外,还可以执行计划任务特殊的线程要求,比如:scheduleWithFixedDelay(command, initialDelay, delay, unit);在初始化延迟之后,以特定的延迟时间重复执行。scheduleAtFixedRate(command, initialDelay, period, unit);在初始化延迟时间之后,以固定频率重复执行。这两种的区别是下一次执行时间延迟计算的开始时间不同,第一种是从上一次任务开始执行的时候计算,第二种是从上一次任务执行结束的时候计算。这两种和java之前版本中Timer类很相似。但是Timer有很多缺陷,具体的缺陷不再详细说明。而这些缺陷都可以通过ScheduledExecutorService给完美解决。所以是时候该丢弃Timer了。
浏览: 109186 次
来自: 武汉
springmvc3.2之后原生支持日期转换 不需要加jota ...
wuyuetiank 写道需要什么jar ??我把代码贴进去H ...
需要什么jar ??我把代码贴进去HttpClients这个报 ...
谢谢,学习下
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'java 使用线程定时执行任务的简单例子 - 为程序员服务
为程序员服务
使用线程定时执行任务的简单例子
servlet 在服务器启动时开始启动线程
&servlet-name&TestThread&/servlet-name&
&servlet-class&com.tplife.iweb.model.TestThread&/servlet-class&
&load-on-startup&0&/load-on-startup&
&/servlet&
public class ThreadTest extends HttpServlet implements Runnable {
public void run() {
while(true){
c=Calendar.getInstance();//时间对象
int mm=30;//默认线程间隔时间
System.out.println(&mm:&+mm+&
time:&+c.get(Calendar.SECOND));
//初始第一次的间隔时间
if(c.get(Calendar.SECOND)%30!=0)
System.out.println(&第一次间隔时间设置&);
mm=60-c.get(Calendar.SECOND);
System.out.println(&mm:&+mm);
Thread.sleep(mm*1000L);
if(c.get(Calendar.SECOND)==0)//条件执行
System.out.println(&run Thread&);
} catch (InterruptedException e) {
e.printStackTrace();
public void init() throws ServletException {
System.out.println(&------------Thread init()-------------&);
ThreadTest t=new ThreadTest();
new Thread(t).start();
public static void main(String[] args) {
Calendar c=Calendar.getInstance();
System.out.println(c.get(Calendar.SECOND));
ThreadTest t=new ThreadTest();
new Thread(t).start();
//该片段来自于http://outofmemory.cn
您可能的代码
相关聚客文章
荣誉:1062
相关专栏文章在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
标签:至少1个,最多5个
在现实世界里,我们总是免不了要定期去做一件事情(比如上课)—— 在计算机的世界里,更是如此。比如我们手机每天叫我们起床的电子闹钟,某些网站会定期向我们发送一些推荐相关的邮件,集群中我们需要每隔一定时间检查是否有机器宕机等。
中已经介绍,JDK 1.5 时,标准类库添加了对线程池的支持,然后在线程池核心实现 ThreadPoolExecutor 的基础上,实现了 ScheduledThreadPoolExecutor,作为可以 定时和周期性执行任务 的线程池。ScheduledThreadPoolExecutor 的类图如下:
ScheduledThreadPoolExecutor 实现了 ScheduledExecutorService 接口,ScheduledExecutorService 继承了 ExecutorService 接口,所以首先 ScheduledThreadPoolExecutor 是一个 ExecutorService (线程池),然后除了具有线程池的功能,它还有定时和周期性执行任务的功能。ScheduledExecutorService 除了从 ExecutorService 继承的方法外,还包括如下四个方法:
第一个 Schedule 方法:
delay 指定的时间后,执行指定的 Runnable 任务,可以通过返回的 ScheduledFuture&?& 与该任务进行交互。
第二个 Schedule 方法:
delay 指定的时间后,执行指定的 Callable&V& 任务,可以通过返回的 ScheduledFuture&V& 与该任务进行交互。
(ScheduledFuture 接口 继承自 Future 接口,所以 ScheduledFuture 和任务的交互方式与 Future 一致。所以通过ScheduledFuture,可以 判断定时任务是否已经完成,获得定时任务的返回值,或者取消任务等)
scheduleAtFixedRate 方法:
initialDelay 指定的时间后,开始按周期 period 执行指定的 Runnable 任务。假设调用该方法后的时间点为 0,那么第一次执行任务的时间点为 initialDelay,第二次为 initialDelay + period,第三次为 initialDelay + period + period,以此类推。
scheduleWithFixedDelay 方法:
initialDelay 指定的时间后,开始按指定的 delay 延期性的执行指定的 Runnable 任务。假设调用该方法后的时间点为 0,每次任务需要耗时 T(i)(i 为第几次执行任务),那么第一次执行任务的时间点为 initialDelay,第一次完成任务的时间点为 initialDelay + T(1),则第二次执行任务的时间点为 initialDelay + T(1) + delay;第二次完成任务的时间点为 initialDelay + (T(1) + delay) + T(2),所以第三次执行任务的时间点为 initialDelay + T(1) + delay + T(2) + delay,以此类推。
我们来实践下 ScheduledThreadPoolExecutor 的 scheduleAtFixedRate 方法:
public class ScheduledExecutorServiceTest {
public static void main(String[] args) throws Exception {
ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
TimerTask timerTask = new TimerTask(2000); // 任务需要 2000 ms 才能执行完毕
System.out.printf("起始时间:%s\n\n", new SimpleDateFormat("HH:mm:ss").format(new Date()));
// 延时 1 秒后,按 3 秒的周期执行任务
timer.scheduleAtFixedRate(timerTask, , TimeUnit.MILLISECONDS);
private static class TimerTask implements Runnable {
private final int sleepT
private final SimpleDateFormat dateF
public TimerTask(int sleepTime) {
this.sleepTime = sleepT
dateFormat = new SimpleDateFormat("HH:mm:ss");
public void run() {
System.out.println("任务开始,当前时间:" + dateFormat.format(new Date()));
System.out.println("模拟任务运行...");
Thread.sleep(sleepTime);
} catch (InterruptedException ex) {
ex.printStackTrace(System.err);
System.out.println("任务结束,当前时间:" + dateFormat.format(new Date()));
System.out.println();
运行结果:
可以看到运行结果完全符合预期 —— 延时 1 秒后,每隔 3 秒执行一次任务。
上面是任务的运行时间小于周期时间的情况 —— 那如果任务运行的时间大于给定的执行周期呢?(比如任务运行需要 3 s,但是我们指定的周期为 2 s)
修改 main 方法:
public static void main(String[] args) throws Exception {
ScheduledExecutorService timer = Executors.newScheduledThreadPool(2);
TimerTask timerTask = new TimerTask(3000); // 每个任务需要 3000 ms 才能执行完毕
System.out.printf("起始时间:%s\n\n", new SimpleDateFormat("HH:mm:ss").format(new Date()));
timer.scheduleAtFixedRate(timerTask, , TimeUnit.MILLISECONDS);
运行结果:
可以看到此时虽然我们指定的周期为 2 s,但是因为任务的运行就需要 3 s(超过周期),所以这种情况下 scheduleAtFixedRate 的处理方式为 上一次任务刚完成,则紧接着立即运行下一次任务,而不是使用线程池中的空闲线程来运行任务以维护 2 秒这个周期 —— 由此可见,每个定时任务在 ScheduledThreadPoolExecutor 中,都是串行运行的,即下一次运行任务一定在上一次任务结束之后。
(scheduleWithFixedDelay 方法 的使用也十分简单,请有兴趣的读者自己实践)
1 收藏&&|&&9
你可能感兴趣的文章
5 收藏,631
4 收藏,333
4 收藏,866
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
分享到微博?
我要该,理由是:
在 SegmentFault,学习技能、解决问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。一、任务和线程
  《thinking in java》中专门有一小节中对线程和任务两个概念进行了具体的区分,这也恰好说明任务和线程是有区别的。
  正如前文所提到的,任务只是一段代码,一段要达成你目的的代码,这段代码写在哪,怎么写其实无所谓,只是因为你希望java的多线程机制能够识别并调用你编写的任务,所以规定了Runnable接口,让你的任务来实现该接口,把你想做的工作在实现该接口的run方法中实现。
  那么,已经定义了任务类,那任务和线程有什么关系呢?
  java的线程是用来驱动任务执行的,也就是说你得把任务挂载到一个线程上,这样该线程才能驱动你定义的任务来执行。
二、定义线程
  1.显示的定义线程的过程就是将任务附着到线程的过程。线程Thread自身并不执行任何操作,它只是用来被多线程机制调用,并驱动赋予它的任务。
  如前次文章提到的任务类定义如下:
public class Task implements Runnable {
protected int countDown = 10;
private static int taskCount = 0 ;
private final int id = taskCount++;
public Task(){}
public Task(int countDown){
this.countDown = countD
public String status(){
return "#"+id+"("+(countDown&0?countDown:"Task!")+").
public void run() {
while(countDown--&0){
System.out.print(status());
Thread.yield();
  声明线程并将任务附着到该线程上:
Thread t = new Thread(new Task());
  这样,任务就附着给了线程,下面就是让线程启动,只需要如下的调用:
t.start();
  至此,线程声明ok。
  有时,我会想,是不是像任务和线程的概念分离一样,此时只是声明了线程,而java的线程机制并不会调用该线程运行,还需要特殊的调用才能实现多线程执行。但是下面的一段代码告诉我,Thread类的start方法就是触发了java的多线程机制,使得java的多线程能够调用该线程
public static void main(String[] args){
Thread t = new Thread(new Task());
t.start();
System.out.println("Waiting for Task");
输出结果如下:
Waiting for Task
#0(Task!).
  先输出&Waiting for Task&证明调用完start()方法后,立即返回了主程序,并开始执行下面的语句。而你声明的t线程已经去被java的多线程机制调用,并驱动着它的任务运行了。
  2.补充
  想看到更多的线程任务运行,可以用下面的这段代码
public static void main(String[] args){
for(int i = 0 ; i & 5 ; i++){
new Thread(new Task()).start();
System.out.println("Waiting for Task");
  输出如下:
Waiting for Task
#2(Task!).
#4(Task!).
#0(Task!).
#3(Task!).
#1(Task!).
  上面的输出说明不同任务的执行在线程被换进换出时混在了一起&&由线程调度器自动控制。不同版本的jdk线程调度方式不同,所以产生的结果也不相同。
  这里涉及了垃圾回收器的一个问题,每个Thread都注册了它自己,因此确实有一个对它的引用,而且在它的任务退出其run并死亡之前,垃圾回收器无法清除它。
注:以上代码均来自《thinking in java》,内容大部分是个人理解和总结,如有错误请各位指正
阅读(...) 评论()}

我要回帖

更多关于 java多线程定时任务 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信