java多线程创建-Thread,Runnable,callable和threadpool
java创建多线程的方式有许多种,这里简要做个梳理
1. 继承Thread类
继承java.lang.Thread类,创建本地多线程的类,重载run()方法,调用Thread的方法启动线程。示例代码如下:
MyThread.java
public class MyThread extends Thread {
public void run(){
private int copy = 0;
System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());
System.out.println("Thread serialnum:" + ++copy);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());
}
public static void main(String[] args){
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
System.out.println("Start all Threads:");
mt1.start();
mt2.start();
mt3.start();
}
}
输出结果:
Start all Threads:
Thread id:Thread-0 == print time:1495975884383
Thread serialnum:1
Thread id:Thread-1 == print time:1495975884383
Thread serialnum:1
Thread id:Thread-2 == print time:1495975884383
Thread serialnum:1
Thread id:Thread-1 == print time:1495975885385
Thread id:Thread-0 == print time:1495975885385
Thread id:Thread-2 == print time:1495975885385
2. 实现Runnable接口
实现java.lang.Runnable接口的run方法,使用实现的对象实例化Thread类,调用Thread对象的start()方法。
示例代码:
public class MyRunnable implements Runnable {
private int copy = 0;
public void run(){
System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());
System.out.println("Thread serialnum:" + ++copy);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis());
}
public static void main(String[] args){
MyRunnable mr = new MyRunnable();
System.out.println("Start all Threads:");
new Thread(mr).start();
new Thread(mr).start();
new Thread(mr).start();
}
}
输出结果:
Start all Threads:
Thread id:Thread-0 == print time:1495975833588
Thread id:Thread-1 == print time:1495975833588
Thread serial:1
Thread id:Thread-2 == print time:1495975833588
Thread serial:2
Thread serial:3
Thread id:Thread-0 == print time:1495975834603
Thread id:Thread-1 == print time:1495975834603
Thread id:Thread-2 == print time:1495975834603
对比Thread方法和Runnable方法的使输出结果不难发现:
. 二者均可实现多线程并发效果
. Runnable的方法可以使用一个Runnable对象创建多个线程,这多个线程共享其依赖的Runnable对象的资源,适用于多个线程处理相同资源的场景(网上举得较多的例子:卖票);Thread的方法则是完全相互独立的线程
事实上,嫌贵而言,当前Runnable使用的要比Thread方法普遍的多,除了上面说的资源共享的原因之外,Java的单继承特性也增大了Thread方法的局限性。
3. 实现Callable接口
相对于上述继承Thread类的方法和实现Runnable接口的方法,实现Callable接口的方法不但可以可以实现多线程并发,还能够处理线程的返回值或者获取执行异常。使用Callable实现多线程编程需要实现Callable的call方法(在call方法中指定返回值,抛出异常),构造与之关联的FutureTask对象,启动线程后,线程执行的结果会存储在FutureTask对象中,可以使用FutureTask的get方法获取。示例代码:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import static java.lang.Thread.sleep;
public class MyCallable implements Callable<Integer> {
private int flag = 0;
public Integer call() throws Exception {
System.out.println("Thread id:" + Thread.currentThread().getName() + " == print time:"+System.currentTimeMillis());
sleep(10000);
System.out.println("Thread id:" + Thread.currentThread().getName() + " == print time:"+System.currentTimeMillis());
++flag;
return flag;
}
public static void main(String[] args) throws Exception{
MyCallable myCallable = new MyCallable();
FutureTask<Integer> future = new FutureTask<Integer>(myCallable);
FutureTask<Integer> future2 = new FutureTask<Integer>(myCallable);
new Thread(future).start();
new Thread(future2).start();
int Result,Result2;
// while (!future.isDone());
Result = future.get();
//
// while(!future2.isDone());
Result2 = future2.get();
System.out.println("GET THREAD NAME:"+ Result );
System.out.println("GET THREAD NAME 2:"+Result2);
}
}
执行结果:
Thread id:Thread-0 == print time:1495997744617
Thread id:Thread-1 == print time:1495997744617
Thread id:Thread-0 == print time:1495997754625
Thread id:Thread-1 == print time:1495997754625
GET THREAD NAME:1
GET THREAD NAME 2:2
上述代码执行逻辑与前面Runnale的示例代码类似,通过构造Thread对象来启动多线程。区别在于此处构造了futureTask方法用来用来存储线程返回值。需要注意的是,线程的Callable泛型接口里的类型和call()方法的返回值类型和FutureTask的泛型接口类型要一致。
4. 使用线程池和Executor框架
前面的三种方案,我们创建了Runnable或者Callable或者Thread的任务,扔到Thread中去启动,我们需要手动去管理各种多线程的参数,比如线程数量,线程复用,线程安全的控制等。Java5以后的版本提供了Executor技术,能够提供搭建好的线程池,为多线程提供了完整的解决方案,能够有效的管理线程数量,线程复用策略,保证线程安全,避免this逃逸问题等。
Executor提供的线程池方案包括newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool和SingleThreadExecutor(Fork/Join框架还提供了一个newWorkStealingPool),这些线程池分别提供了不同的线程管理方案,执行返回一个ExecutorService对象,这个对象可以调用execute()方法或者submit()方法,将前面定义的Runnable任务或者Callable任务或者Thread任务提交到各个线程去执行
我们以比较常用的newCachedThreadPool()为例,下面示例代码使用ExecutorService执行一个Callable对象任务,获取每个线程的返回值。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import static java.lang.Thread.sleep;
public class MyCallable2 implements Callable<String> {
public String call() throws Exception{
sleep(1000);
System.out.println("terminate the thread : "+Thread.currentThread().getName());
return Thread.currentThread().getName();
}
public static void main(String[] args){
ExecutorService es = Executors.newCachedThreadPool();
List<Future<String>> futureList = new ArrayList<Future<String>>();
for(int i=0;i<5;i++){
Future future = es.submit(new MyCallable2());
futureList.add(future);
}
for (Future f: futureList
) {
while(!f.isDone());
try {
System.out.println("EXECUTE RESULT:"+f.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
finally {
es.shutdown();
}
}
}
}
执行结果如下:
terminate the thread : pool-1-thread-5
terminate the thread : pool-1-thread-4
terminate the thread : pool-1-thread-3
terminate the thread : pool-1-thread-2
terminate the thread : pool-1-thread-1
EXECUTE RESULT:pool-1-thread-1
EXECUTE RESULT:pool-1-thread-2
EXECUTE RESULT:pool-1-thread-3
EXECUTE RESULT:pool-1-thread-4
EXECUTE RESULT:pool-1-thread-5
使用Executors创建Runnable线程与创建Callable线程的方法类似,且不用管理返回值,相对更加简单,此处不再赘述。
java多线程创建-Thread,Runnable,callable和threadpool的更多相关文章
- JAVA多线程(一) Thread & Runnable
githut代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-service/ ...
- Java 多线程实现接口Runnable和继承Thread区别(转)
Java 多线程实现接口Runnable和继承Thread区别 Java中有两种实现多线程的方式.一是直接继承Thread类,二是实现Runnable接口.那么这两种实现多线程的方式在应用上有什么区别 ...
- Java多线程01(Thread类、线程创建、线程池)
Java多线程(Thread类.线程创建.线程池) 第一章 多线程 1.1 多线程介绍 1.1.1 基本概念 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于 ...
- Java 多线程(1)-Thread和Runnable
一提到Java多线程,首先想到的是Thread继承和Runnable的接口实现 Thread继承 public class MyThread extends Thread { public void ...
- java多线程(二)-Runnable和Thread
Java在顺序性语言的基础上提供了多线程的支持.Java的线程机制是抢占式的.这表示调度机制会周期的中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片.(与抢占式多线程对应的是 协作式多线 ...
- Java多线程中的Runnable和Thread
摘要: 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的r ...
- Java多线程-----创建线程的几种方式
1.继承Thread类创建线程 定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体 创建Thread子类的实例,也就是创建 ...
- java多线程-创建线程
大纲: Thread创建线程. Runnable接口. Callable接口. 小结 一.java创建线程--继承Thead类 创建一个类继承Thead类,并重写run方法. class Test { ...
- Java多线程——创建线程的两种方式
创建线程方式一:继承Thread类. 步骤:1,定义一个类继承Thread类.2,覆盖Thread类中的run方法.3,直接创建Thread的子类对象创建线程.4,调用start方法开启线程并调用线程 ...
随机推荐
- Java中Math.round()函数
Math.round(11.5) = 12; Math.round(-11.5) = -11; Math.round()函数是求某个数的整数部分,且四舍五入.
- zoj3961(区间问题)
点击打开zoj1961Let's Chat Time Limit: 1 Second Memory Limit:65536 KB ACM (ACMers' Chatting Messenge ...
- PDO浅谈之php连接mysql
一.首先我们先说一下什么是pdo? 百科上说 PDO扩展为PHP访问数据库定义了一个轻量级的.一致性的接口,它提供了一个数据访问抽象层,这样,无论使用什么数据库,都可以通过一致的函数执行查询和获取数 ...
- 传统 HTML 表单数据的“整存整取”
在日常开发中,涉及表单的处理司空见惯.过往,在取值和赋值的过程中,借助 jQuery 常常只是逐个控件进行操作,可惜这样开发效率并不高.那么能不能批量获取整个表单的值呢,以及批量为表单赋值. 一.取值 ...
- [js高手之路]html5 canvas动画教程 - 自己动手做一个类似windows的画图软件
这个绘图工具,我还没有做完,不过已经实现了总架构,以及常见的简易图形绘制功能: 1,可以绘制直线,圆,矩形,正多边形[已完成] 2,填充颜色和描边颜色的选择[已完成] 3,描边和填充功能的选择[已完成 ...
- php 守护进程类
最近个人项目中需要后台运行任务,之前一直是用nouhp & + 重定向输出 来后台跑任务,后来觉得不好维护原始数据,同时可能也没有直接操作进程那么稳吧(没验证).废话少说,来看分析. 首先,我 ...
- JSP中的九大隐式对象及四个作用域
在这篇博文中,我们将讨论和学习JSP中的隐式对象及四个作用域. 一.九大隐式对象 这些对象是JSP容器为每个页面中的开发人员提供的Java对象,开发人员可以直接调用它们而不用显式地声明它们再调用. J ...
- C陷阱和缺陷学习笔记
这段时间把<C陷阱和缺陷>看了,没时间自己写总结.就转一下别人的学习笔记吧http://bbs.chinaunix.net/thread-749888-1-1.html Chapter 1 ...
- Yii2之属性
一直以来,在我的理解中,类的成员变量和属性就是同一个东西,直到看了<深入理解Yii2.0>才明白,类的成员变量和属性其实不是同一个概念,成员变量是就类的结构构成而言的概念,而属性是就类的功 ...
- python matplotlib 图表局部放大
import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes ...