Android(java)学习笔记66:实现Runnable接口创建线程 和 使用Callable和Future创建线程
1. 前面说的线程的实现是新写一个子类继承Thread:
是将类声明为 Thread
的子类。该子类应重写 Thread
类的 run
方法。接下来可以分配并启动该子类的实例
2. 这里说的方案2是指实现一个接口:
是声明实现 Runnable
接口的类。该类然后实现 run
方法。然后可以分配该类的实例,在创建 Thread
时作为一个参数来传递并启动。
这里我们主要说明2的实现方式…………
package cn.itcast_05; public class MyRunnable implements Runnable { @Override
public void run() {
for (int x = 0; x < 100; x++) {
// 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
System.out.println(Thread.currentThread().getName() + ":" + x);
}
} }
package cn.itcast_05; /*
* 方式2:实现Runnable接口
* 步骤:
* A:自定义类MyRunnable实现Runnable接口
* B:重写run()方法
* C:创建MyRunnable类的对象
* D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
*/
public class MyRunnableDemo {
public static void main(String[] args) {
// 创建MyRunnable类的对象
MyRunnable my = new MyRunnable(); // 创建Thread类的对象,并把C步骤的对象作为构造参数传递
// Thread(Runnable target)
// Thread t1 = new Thread(my);
// Thread t2 = new Thread(my);
// t1.setName("林青霞");
// t2.setName("刘意"); // Thread(Runnable target, String name)
Thread t1 = new Thread(my, "林青霞");
Thread t2 = new Thread(my, "刘意"); t1.start();
t2.start();
}
}
3. 方案3:使用Callable和Future创建线程
前面实现Runnable接口创建多线程时候,Thread类的作用是把run()方法包装成线程执行体。那么是否可以直接把任意方法都包装成线程执行体呢?
Java目前不行的,但是Java的模仿者C#可以(C#可以将任意方法包装成线程执行体,包括有返回值的方法)
也许受此启发,从Java5开始,Java提供了Callable接口,该接口可以看成是Runnable接口的增强版,Callable接口提供了一个call()方法可以作为线程执行体,但是call()方法比run()方法功能更加强大。
- call()方法可以有返回值。
- call()方法可以声明抛出异常
因此完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是该Callable对象的call()方法。
问题是:Callable接口是Java 5新增的接口,而且它不是Runnable接口的子接口,所以Callable对象不能直接作为Thread的target。而且call()方法还有一个返回值---call()方法并不是直接调用的,它是作为线程执行体被调用的,那么如何获取call()方法的返回值呢?
Java 5提供了Future接口来代表Callable接口里call()方法的返回值,并为Future接口提供一个FutureTask实现类,该实现类实现了Future接口,并实现了Runnable接口---可以作为Thread类的target。
在Future接口里定义了如下几个公共方法来控制它关联的Callable任务:
- boolean cancel(boolean mayInterruptIfRunning):试图取消该Future里关联的Callable任务。
- V get():返回Callable任务里面call()方法的返回值。调用该方法将导致程序阻塞,必须等到子线程结束之后才会得到返回值
- V get(long timeout, TimeUnit unit):返回Callable任务里call()方法的返回值。该方法让程序最长阻塞时间由timeout 和 unit指定的时间,如果经过指定时间后Callable任务依然没有返回值,将会抛出TimeoutException异常
- boolean isCancelled():如果在Callable任务正常完成前取消,则返回true。
- boolean isDone():如果Callable任务已完成,则返回true。
使用Callable和Future创建线程的步骤:
(1)创建Callable接口实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值,在创建Callable实现类的实例。
(2)使用FutureTask类包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值
(3)使用FutureTask对象作为Thread对象target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
示例1:
package com.himi.threadcallable; import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask; public class CallableAndFutureDemo1 {
public static void main(String[] args) { Callable<Integer> callable = new Callable<Integer>() {
public Integer call() throws Exception {
return new Random().nextInt(100);
}
}; FutureTask<Integer> future = new FutureTask<Integer>(callable); new Thread(future).start(); try {
Thread.sleep(5000);// 可能做一些事情
System.out.println(future.get());//子线程执行结束,获取返回值
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
执行结果,如下:
FutureTask实现了两个接口,Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值,那么这个组合的使用有什么好处呢?假设有一个很耗时的返回值需要计算,并且这个返回值不是立刻需要的话,那么就可以使用这个组合,用另一个线程去计算返回值,而当前线程在使用这个返回值之前可以做其它的操作,等到需要这个返回值时,再通过Future得到,岂不美哉!
示例2:
package com.himi.threadcallable; import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; public class CallableAndFutureDemo2 {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
Future<Integer> future = threadPool.submit(new Callable<Integer>() {
public Integer call() throws Exception {
return new Random().nextInt(100);
}
});
try {
Thread.sleep(5000);// 可能做一些事情
System.out.println(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
运行效果,如下:
代码是不是简化了很多,ExecutorService继承自Executor,它的目的是为我们管理Thread对象,从而简化并发编程,Executor使我们无需显示的去管理线程的生命周期,是JDK 5之后启动任务的首选方式。
4. 总结:
实现多线程的方式:3种
• 方式1:继承Thread类
A:自定义类MyThread继承Thread类
B:在MyThread类中重写run().
C:创建MyThread类的对象.
D: 启动线程对象
问题
a:为什么要重写run()方法?
run()里面封装的是被线程执行的代码
b:启动线程对象要哪个方法?
start()
c:run()和start()方法的区别?
run()直接调用的仅仅是普通方法
start()先启动线程,再由JVM调用run()方法
• 方式2:实现Runnable接口
A:自定义类MyRunnable实现Runnable接口.
B:在MyRunnable里面重写run()
C:创建MyRunnable类的对象
D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
• 方式3:使用Callable 和 Future创建线程
步骤在上面。
问题来了1:有了方式1,为什么还来方式2呢 ?
a:可以避免由于Java单继承带来的局限性.
b:适合多个相同程序代码去处理同一个资源的情况,把线程同程序的代码、数据有效分离,较好的体现了面向对象的设计思想。
Android(java)学习笔记66:实现Runnable接口创建线程 和 使用Callable和Future创建线程的更多相关文章
- Android(java)学习笔记6:实现Runnable接口创建线程 和 使用Callable和Future创建线程
1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...
- [core java学习笔记][第六章接口与内部类]
接口域内部类 接口 描述类具有什么功能,不给出具体实现. 内部类 用于设计协作关系的类集合 代理 实现任意接口的对象. 6.1 接口 接口声明 public interface Comparable ...
- java学习笔记23(Set接口)
Set接口: 1.Set接口是不包含重复元素的Collection: 2.set集合没有索引,只能通过增强型for循环或迭代器来遍历: 3.Set接口只包含从collection接口继承的方法,并且增 ...
- Java学习笔记22(List接口)
List接口继承自Collection接口,自身具有三大特点: 1.有序集合:存入和取出的顺序一致: 2.此接口的用户可以对每个元素插入位置进行精确控制:可以通过索引操作元素 3.可以存储重复元素 L ...
- java学习笔记—ServletConfig、ServletContext接口(13)
ServletConfig是一个由Tomcat服务器在初始化Servlet的时候创建并传递进来的一个对象. 该对象主要描述的时候一个servlet的配置信息. 如: <servlet> ...
- Java学习笔记之抽象类与接口
抽象类(abstract) 抽象类概述:一个类被abstract修饰表示这个类是抽象类, 自己定义方法但是不实现方法,后代去实现 抽象方法: 一个方法被abstract修饰表示这个方法是抽象方法 ...
- 0026 Java学习笔记-面向对象-抽象类、接口
抽象方法与抽象类 抽象方法用abstract修饰,没有方法体部分,连花括号都不能有: 抽象方法和抽象类都用abstract修饰 包含抽象方法的类一定是抽象类:但不包含抽象方法的类也可以是抽象类 不能创 ...
- 【Java学习笔记】HashMap子接口---LinkedHashMap
特点: 存入元素的顺序 与 取出元素的顺序相同(与LinkedHashSet类似) import java.util.HashMap; import java.util.Iterator; i ...
- Java学习笔记——MySQL开放3306接口与设置用户权限
系统Ubuntu16.04 LTS 1.开放3306端口查看端口状态:netstat -an|grep 3306tcp 0 0 127.0.0.1:3306 ...
随机推荐
- poj 1797 Heavy Transportation(Dijkstar变形)
http://poj.org/problem?id=1797 给定n个点,及m条边的最大负载,求顶点1到顶点n的最大载重量. 用Dijkstra算法解之,只是需要把“最短路”的定义稍微改变一下, A到 ...
- JS初识(着重讲解Date函数)
查看类型:typeof() 转换为int类型:parseInt() isNaN() 函数用于检查其参数是否是非数字值. NaN,是Not a Number的缩写.一种计算机用语.NaN 用于处理计算中 ...
- UITextFiled,UIButton,UIImageView交互相互之间的事件拦截
UIButton右上方添加一个笑button如: UIButton *button =[UIButton buttonWithType:UIButtonTypeCustom]; button.f ...
- 开源文件比较工具:WinMerge、KDiff3、diffuse
为了寻找免费的BeyondCompare的替代品,最后经过实用,找到如下一些: 1.diffuse 感受:如果仅仅是比较两个文本类的文件,这个软件也就够用了. 安装好后,对着文件点击右键,会出现“Op ...
- C语言的struct/union字节对齐
C语言的一大优势就是对内存空间的控制,当然,一般情况下对于开发人员来说都是透明的.看一个始终困扰初学者的问题:字节对齐! 先看四个重要的基本概念:1.数据类型自身的对齐值:对于char型数据,其自身对 ...
- [转][IIS]发布网站,提示用户 'IIS APPPOOL\***' 登录失败。
链接:http://www.cnblogs.com/tianguook/p/3881075.html 用户 'IIS APPPOOL\DefaultAppPool' 登录失败. 我在windows8中 ...
- Linux下 如何正确配置 Nginx + PHP
假设我们用PHP实现了一个前端控制器,或者直白点说就是统一入口:把PHP请求都发送到同一个文件上,然后在此文件里通过解析「REQUEST_URI」实现路由. 一般这样配置 此时很多教程会教大家这样配置 ...
- mvc web api 保存多个实体类的方法
先说一下我的业务需求,挺简单的. 就是在设计角色和权限的页面中,需要一个角色对应多条权限记录,那么在保存的时候,我的处理方式是,先删除该角色的所有权限,然后再保存所有的权限. 这样的话问题就来了,用默 ...
- Spring三种实例化Bean的方法
1.实例化bean的三种方法:(1) 构造器<!-- 体验1 --><bean id="personService" class="com.persia ...
- C++的优秀特性1:引用
(转载请注明原创于潘多拉盒子) 一本典型的C语言教科书的厚度大约是200页左右,而一本典型的C++教科书的厚度至少要500页.比如K&R的<The C Programming Langu ...