3种方式实现Java多线程
java中实现多线程的方法有两种:继承Thread类和实现runnable接口。
1.继承Thread类,重写父类run()方法
public class thread1 extends Thread { public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("我是线程"+this.getId());
}
} public static void main(String[] args) {
thread1 th1 = new thread1();
thread1 th2 = new thread1();
th1.run();
th2.run();
}
}
run()方法只是普通的方法,是顺序执行的,即th1.run()执行完成后才执行th2.run(),这样写只用一个主线程。多线程就失去了意义,所以应该用start()方法来启动线程,start()方法会自动调用run()方法。上述代码改为:
public class thread1 extends Thread { public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println("我是线程"+this.getId());
}
} public static void main(String[] args) {
thread1 th1 = new thread1();
thread1 th2 = new thread1();
th1.start();
th2.start();
}
}
通过start()方法启动一个新的线程。这样不管th1.start()调用的run()方法是否执行完,都继续执行th2.start()如果下面有别的代码也同样不需要等待th2.start()执行完成,而继续执行。(输出的线程id是无规则交替输出的)
2.实现runnable接口
public class thread2 implements Runnable { public String ThreadName; public thread2(String tName){
ThreadName = tName;
} public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(ThreadName);
}
} public static void main(String[] args) {
thread2 th1 = new thread2("线程A");
thread2 th2 = new thread2("线程B");
th1.run();
th2.run();
}
}
和Thread的run方法一样Runnable的run只是普通方法,在main方法中 th2.run()必须等待th1.run()执行完成后 才能执行,程序只用一个线程。要多线程的目的,也要通过Thread的start()方法(注:runnable是没有start方法)。上述代码修改 为:
public class thread2 implements Runnable { public String ThreadName; public thread2(String tName){
ThreadName = tName;
} public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(ThreadName);
}
} public static void main(String[] args) {
thread2 th1 = new thread2("线程A");
thread2 th2 = new thread2("Thread-B");
Thread myth1 = new Thread(th1);
Thread myth2 = new Thread(th2);
myth1.start();
myth2.start();
}
}
3.使用ExecutorService、Callable、Future实现有返回结果的多线程(JDK5.0以后)
可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。执行Callable任务后,可以获
取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口
ExecutorService就可以实现传说中有返回结果的多线程了。下面提供了一个完整的有返回结果的多线程测试例子,在JDK1.5下验证过没问题
可以直接使用。代码如下:
import java.util.concurrent.*;
import java.util.Date;
import java.util.List;
import java.util.ArrayList; /**
* 有返回值的线程
*/
@SuppressWarnings("unchecked")
public class Test {
public static void main(String[] args) throws ExecutionException,
InterruptedException {
System.out.println("----程序开始运行----");
Date date1 = new Date(); int taskSize = 5;
// 创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 创建多个有返回值的任务
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new MyCallable(i + " ");
// 执行任务并获取Future对象
Future f = pool.submit(c);
// System.out.println(">>>" + f.get().toString());
list.add(f);
}
// 关闭线程池
pool.shutdown(); // 获取所有并发任务的运行结果
for (Future f : list) {
// 从Future对象上获取任务的返回值,并输出到控制台
System.out.println(">>>" + f.get().toString());
} Date date2 = new Date();
System.out.println("----程序结束运行----,程序运行时间【"
+ (date2.getTime() - date1.getTime()) + "毫秒】");
}
}
class MyCallable implements Callable<Object> {
private String taskNum; MyCallable(String taskNum) {
this.taskNum = taskNum;
} public Object call() throws Exception {
System.out.println(">>>" + taskNum + "任务启动");
Date dateTmp1 = new Date();
Thread.sleep(1000);
Date dateTmp2 = new Date();
long time = dateTmp2.getTime() - dateTmp1.getTime();
System.out.println(">>>" + taskNum + "任务终止");
return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
}
}
代码说明:
上述代码中Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。
public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。
ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其它线程执行的任务。
Callable和Runnable有几点不同:、
①Callable规定的方法是call(),而Runnable规定的方法是run().
②Callable的任务执行后可返回值,而Runnable的任务是不能返回值的
③call()方法可抛出异常,而run()方法是不能抛出异常的。
④运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等
待计算的完成,并检索计算的结果.通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果
总结:实现java多线程的2种方式,runable是接口,thread是类,runnable只提供一个run方法,建议使用runable实现 java多线程,不管如何,最终都需要通过thread.start()来使线程处于可运行状态。
3种方式实现Java多线程的更多相关文章
- java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
转载地址:http://www.devba.com/index.php/archives/4581.html java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明); ...
- (转)java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 1. java向MySQL插入当前时间的四种方式 第一种:将java.util.Date ...
- 两种方式实现java生成Excel
Web应用中难免会遇到需要将数据导出并生成excel文件的需求.同样,对于本博客中的总结,也是建立在为了完成这样的一个需求,才开始去了解其实现形式,并且顺利完成需求的开发,先将实现过程总结于此.本博文 ...
- Struts 2 实现Action的几种方式_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 Action用于处理用户的请求,因此也被称为业务控制器.每个Action类就是一个工作单元,Struts 2框架负责将用 ...
- 五种方式实现 Java 单例模式
前言 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创建自 ...
- 设置JVM参数的几种方式解决java.lang.OutOfMemoryError:Java heap space
一.首先给出查询当前JVM内存的代码: 下面是查询当前JVM 内存大小的代码,可以测试设置后JVM 的内存是否会变化.增加JVM 内存的配置项后,无需重新启动eclipse .具体的代码如下: pub ...
- java 下载文件的两种方式和java文件的上传
一:以网络的方式下载文件 try { // path是指欲下载的文件的路径. File file = new File(path); // 以流的形式下载文件. InputStream fis = n ...
- (分享)java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
原文地址 http://blog.csdn.net/yangkai_hudong/article/details/18705713
- 3种方式实现python多线程并发处理
标签: python奇淫技巧 最优线程数 Ncpu=CPU的数量 Ucpu=目标CPU使用率 W/C=等待时间与计算时间的比率 为保持处理器达到期望的使用率,最优的线程池的大小等于$$Nthreads ...
随机推荐
- Ecshop 安装时错误
网上提示方法将install/includes/lib_installer.php以下内容修改后仍然提示失败: include(ROOT_PATH . 'install/languages/' . $ ...
- 算法库:基础线性代数子程序库(Basic Linear Algebra Subprograms,BLAS)介绍
调试DeepFlow光流算法,由于作者给出的算法是基于Linux系统的,所以要在Windows上运行,不得不做大量的修改工作.移植到Windows平台,除了一些头文件找不到外,还有一些函数也找不到.这 ...
- IntelliJ IDEA设置字符编码为UTF-8
File->Settings->Editor->File Encodings IDE Encoding: UTF-8 Project Encoding: UTF-8
- Android中常用的5大布局详述
Android的界面是有布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当于建筑里的砖瓦.组件按照布局的要求依次排列,就组成了用户所看见的界面. 所有的布局方式都可以归类为ViewGroup的 ...
- 怎样用CODESOFT打印连续的条码标签?
在实际工作中,经常会用CODESOFT条 码打印软件来实现打印连续的条码标签,将这些标签按递增或递减等方式连续打印.这样设置可大大提高用户的工作效率.实现在CODESOFT 2015打印连续条码标签, ...
- 【Unity Shaders】学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert
[Unity Shaders]学习笔记——SurfaceShader(三)BasicDiffuse和HalfLambert 转载请注明出处:http://www.cnblogs.com/-867259 ...
- Effective Modern C++翻译(3)-条款2:明白auto类型推导
条款2 明白auto类型推导 如果你已经读完了条款1中有关模板类型推导的内容,那么你几乎已经知道了所有关于auto类型推导的事情,因为除了一个古怪的例外,auto的类型推导规则和模板的类型推导规则是一 ...
- uitableviewcell高度自适应笔记
今天看了几篇uitableviewcell高度自适应的文章,大体分为两种方式. 第一种方式,cell里面有label,在cellforrow绘制的时候计算Label的可能高度,并且在此时重新计算cel ...
- 从零开始安装Hadoop视频教程
从零开始安装Hadoop视频教程 Hadoop 是一个能够对大量数据进行分布式处理的软件框架,用这种技术使得普通的PC服务器甚至一些近过时的服务器也能够发挥余热,组成大型集群系统,由于它的可伸缩性能够 ...
- 服务器bonding
server cat /etc/sysconfig/network-scripts/ifcfg-bond0 DEVICE=bond0 IPADDR=211.98.243.231 NETMASK=255 ...