java多线程实现runnable很常见如何使用多線程实现runnable,如何创建线程java中有两种方式,第一种是让自己的类实现Runnable接口第二种是让自己的类继承Thread类。其实Thread类自己也是实现了Runnable接口具體使用实例如下:
2、通过继承Thread类的方式
输入结果(每次输入可能不同)不再详细列出。对于上面的两种方式更推荐使用实现Runnable接口的方式實现多线程实现runnable。一方面是可以防止java单继承的顾虑另一方面Runnable是面向接口编程,扩展性比起继承Thread更好所以尽量使用implement Runnable的方式。
二、java线程类型说明
上面是将多线程实现runnable跑起来了但是有个问题,如果不让主线程睡眠当主线程(比如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想停止的时候,不用考虑我这个线程是否执行结束这种线程具体的使用比如在垃圾回收机制的线程,就是一个守护线程
上面已经看过了可以在代码中直接新起线程,如果我们在主线程中新起一百个线程让这一百个线程同时工作,逻辑上是没有任何问题的但是这样做对系统资源的开销很大,这样会在短时间内处理很多的任务当然包括新起线程等等。基于这样的考虑我们是有必要引入线程池这个东西的。线程池就是一个池子池子裏有很多可用线程资源,如果需要就直接从这个池子里拿就是当不用的时候,放入池子中线程池会自动帮我们管理。所以使用线程池主要有以下两个好处:1、减少在创建和销毁线程上所花的时间以及系统资源的开销 2、如不使用线程池有可能造成系统创建大量线程而导致消耗完系统内存 。
如果我们想要使用线程池就需要先定义这个线程池。定义线程池的时候其中的几个主要参数说明如下:
-corePoolSize(int):线程池中保持的线程数量,包括空闲线程在内也就是线程池释放的最小线程数量界限。
-unit(TimeUnit枚举类):上面参数时间的单位可以是分钟,秒毫秒等等。
-handler(RejectedExecutionHandler类):当提交线程拒绝执行、异常的时候处理异常的类。该类取值如下:(注意都是内部类)
除了自定义线程池以外 java提供了几种瑺用的线程池,可以快捷的供程序员使用他们分别是:
2、newSingleThreadExecutor 创建一个线程容量的线程池,所有的线程依次执行相当于创建固定数量为1的線程池。
3、newCachedThreadPool 创建可缓存的线程池没有最大线程限制(实际上是Integer.MAX_VALUE)。如果用空闲线程等待时间超过一分钟就关闭该线程。
4、newScheduledThreadPool 创建计划(延遲)任务线程池,线程池中的线程可以让其在特定的延迟时间之后执行也可以以固定的时间重复执行(周期性执行)。相当于以前的Timer类的使鼡
其实通过静态方法创建的上面几种线程池,也都是通过传入默认的各个参数然后返回一个有各自特点的线程池。具体参数可以通过查看jdk源码阅读
有了线程池,那么我们如何利用线程池中线程执行我们的任务由于Java将线程池的封装,我们拿到的线程池的线程其实是一個包含线程任务的执行器只需要调运执行器的执行方法,就会自动执行我们线程中的任务对于非计划任务,我们需要拿到一个ThreadPoolExecutor对于計划任务,我们需要拿到一个ScheduledThreadPoolExecutor(它是ThreadPoolExecutor的子类)在了解这两个类之前,需要先了解两个接口ExecutorService以及它的子接口ScheduleThreadExecutorService接口,上面两个接口分别实現了这两个接口这个两接口定义了execute(Runnable
unit);在初始化延迟时间之后,以固定频率重复执行这两种的区别是下一次执行时间延迟计算的开始时間不同,第一种是从上一次任务开始执行的时候计算第二种是从上一次任务执行结束的时候计算。这两种和java之前版本中Timer类很相似但是Timer囿很多缺陷,具体的缺陷不再详细说明而这些缺陷都可以通过ScheduledExecutorService给完美解决。所以是时候该丢弃Timer了