1. 前面说的线程的实现是新写一个子类继承Thread:

是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例

2. 这里说的方案2是指实现一个接口:

是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。

这里我们主要说明2的实现方式…………

  1. package cn.itcast_05;
  2. public class MyRunnable implements Runnable {
  3. @Override
  4. public void run() {
  5. for (int x = 0; x < 100; x++) {
  6. // 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
  7. System.out.println(Thread.currentThread().getName() + ":" + x);
  8. }
  9. }
  10. }
  1. package cn.itcast_05;
  2. /*
  3. * 方式2:实现Runnable接口
  4. * 步骤:
  5. * A:自定义类MyRunnable实现Runnable接口
  6. * B:重写run()方法
  7. * C:创建MyRunnable类的对象
  8. * D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
  9. */
  10. public class MyRunnableDemo {
  11. public static void main(String[] args) {
  12. // 创建MyRunnable类的对象
  13. MyRunnable my = new MyRunnable();
  14. // 创建Thread类的对象,并把C步骤的对象作为构造参数传递
  15. // Thread(Runnable target)
  16. // Thread t1 = new Thread(my);
  17. // Thread t2 = new Thread(my);
  18. // t1.setName("林青霞");
  19. // t2.setName("刘意");
  20. // Thread(Runnable target, String name)
  21. Thread t1 = new Thread(my, "林青霞");
  22. Thread t2 = new Thread(my, "刘意");
  23. t1.start();
  24. t2.start();
  25. }
  26. }

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:

  1. package com.himi.threadcallable;
  2. import java.util.Random;
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.FutureTask;
  6. public class CallableAndFutureDemo1 {
  7. public static void main(String[] args) {
  8. Callable<Integer> callable = new Callable<Integer>() {
  9. public Integer call() throws Exception {
  10. return new Random().nextInt(100);
  11. }
  12. };
  13. FutureTask<Integer> future = new FutureTask<Integer>(callable);
  14. new Thread(future).start();
  15. try {
  16. Thread.sleep(5000);// 可能做一些事情
  17. System.out.println(future.get());//子线程执行结束,获取返回值
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. } catch (ExecutionException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

执行结果,如下:

FutureTask实现了两个接口,Runnable和Future,所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值,那么这个组合的使用有什么好处呢?假设有一个很耗时的返回值需要计算,并且这个返回值不是立刻需要的话,那么就可以使用这个组合,用另一个线程去计算返回值,而当前线程在使用这个返回值之前可以做其它的操作,等到需要这个返回值时,再通过Future得到,岂不美哉!

示例2:

  1. package com.himi.threadcallable;
  2. import java.util.Random;
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.ExecutionException;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.Executors;
  7. import java.util.concurrent.Future;
  8. public class CallableAndFutureDemo2 {
  9. public static void main(String[] args) {
  10. ExecutorService threadPool = Executors.newSingleThreadExecutor();
  11. Future<Integer> future = threadPool.submit(new Callable<Integer>() {
  12. public Integer call() throws Exception {
  13. return new Random().nextInt(100);
  14. }
  15. });
  16. try {
  17. Thread.sleep(5000);// 可能做一些事情
  18. System.out.println(future.get());
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. } catch (ExecutionException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }

运行效果,如下:

代码是不是简化了很多,ExecutorService继承自Executor,它的目的是为我们管理Thread对象,从而简化并发编程,Executor使我们无需显示的去管理线程的生命周期,是JDK 5之后启动任务的首选方式。 

4. 总结:

实现多线程的方式:3种

• 方式1:继承Thread类
        A:自定义类MyThread继承Thread类
        B:在MyThread类中重写run().
        C创建MyThread类的对象.
        D 启动线程对象

    问题
           a为什么要重写run()方法?
              run()里面封装的是被线程执行的代码
           b启动线程对象要哪个方法?
          start()
           crun()和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)学习笔记6:实现Runnable接口创建线程 和 使用Callable和Future创建线程的更多相关文章

  1. Android(java)学习笔记66:实现Runnable接口创建线程 和 使用Callable和Future创建线程

    1. 前面说的线程的实现是新写一个子类继承Thread: 是将类声明为 Thread 的子类.该子类应重写 Thread 类的 run 方法.接下来可以分配并启动该子类的实例 2. 这里说的方案2是指 ...

  2. [core java学习笔记][第六章接口与内部类]

    接口域内部类 接口 描述类具有什么功能,不给出具体实现. 内部类 用于设计协作关系的类集合 代理 实现任意接口的对象. 6.1 接口 接口声明 public interface Comparable ...

  3. java学习笔记23(Set接口)

    Set接口: 1.Set接口是不包含重复元素的Collection: 2.set集合没有索引,只能通过增强型for循环或迭代器来遍历: 3.Set接口只包含从collection接口继承的方法,并且增 ...

  4. Java学习笔记22(List接口)

    List接口继承自Collection接口,自身具有三大特点: 1.有序集合:存入和取出的顺序一致: 2.此接口的用户可以对每个元素插入位置进行精确控制:可以通过索引操作元素 3.可以存储重复元素 L ...

  5. java学习笔记—ServletConfig、ServletContext接口(13)

    ServletConfig是一个由Tomcat服务器在初始化Servlet的时候创建并传递进来的一个对象. 该对象主要描述的时候一个servlet的配置信息. 如: <servlet>  ...

  6. Java学习笔记之抽象类与接口

    抽象类(abstract) 抽象类概述:一个类被abstract修饰表示这个类是抽象类, 自己定义方法但是不实现方法,后代去实现 抽象方法:   一个方法被abstract修饰表示这个方法是抽象方法 ...

  7. 0026 Java学习笔记-面向对象-抽象类、接口

    抽象方法与抽象类 抽象方法用abstract修饰,没有方法体部分,连花括号都不能有: 抽象方法和抽象类都用abstract修饰 包含抽象方法的类一定是抽象类:但不包含抽象方法的类也可以是抽象类 不能创 ...

  8. 【Java学习笔记】HashMap子接口---LinkedHashMap

    特点: 存入元素的顺序   与   取出元素的顺序相同(与LinkedHashSet类似) import java.util.HashMap; import java.util.Iterator; i ...

  9. Java学习笔记——MySQL开放3306接口与设置用户权限

    系统Ubuntu16.04 LTS 1.开放3306端口查看端口状态:netstat -an|grep 3306tcp        0      0 127.0.0.1:3306          ...

随机推荐

  1. redis cluster 集群部署

    准备工作 1. 安装docker curl -s https://get.docker.com/ | sh 注:一键安装的事最新版docker.已安装docker可跳过此步骤 2. 获取基础镜像 do ...

  2. Linux kvm虚拟机的基本操作命令

    Linux 虚拟化kvm virsh常用命令篇 1.创建虚拟机 virsh define damo.xml //创建的虚拟机不是活动的 virsh create damo.xml //创建的虚拟机是活 ...

  3. DataGuard具体搭建环节

    在上一篇blog中,详细介绍DataGuard实现的原理,本篇介绍DataGuard的具体搭建过程. 主库打开日志,并强制force logging SQL>shutdown immediate ...

  4. 【Tensorflow】 Object_detection之模型训练日志结果解析

    日志展示 指标说明: AP值表示正确识别物体的个数占总识别出的物体个数的百分数 AR值表示正确识别物体的个数占测试集中物体的总个数的百分数 IoU值即生成的框/掩膜与数据集中的标准的面积之交处于面积之 ...

  5. 介绍几种搭建Dojo环境的方法

    Hello World! 的时间到了,在你所学过的众多语言中,哪个不是从此学起的呢?但在此之前,我们要先构建一个开发环境,如同刚开始学习Java的时候,还是需要我们先安装JDK.配置好环境变量等等,H ...

  6. [转]Mysql几种索引类型的区别及适用情况

    此为转载文章,仅做记录使用,方便日后查看,原文链接:https://www.cnblogs.com/yuan-shuai/p/3225417.html Mysql几种索引类型的区别及适用情况   如大 ...

  7. Linux 连接 Xshell 及网络配置

    一.准备工具 在WMware上已经装有Linux系统:WMware安装CentOS7文章. xshell连接工具: 二.修改相关配置 切换到root用户下: 配置主机名(可选): #方法一:替换原主机 ...

  8. Error creating bean with name 'com.cloud.feign.interfaces.xxxFeignClient': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalSt.PathVariable annotation was empty on

    环境: Spring Cloud:Finchley.M8 Spring Boot:2.0.0.RELEASE 报错信息: Error creating bean with name 'com.clou ...

  9. PAT 1083 List Grades

    #include <cstdio> #include <cstdlib> using namespace std; class Stu { public: ]; ]; }; i ...

  10. CSS之背景的填充范围

    1.资料:CSS2.1 进行了更正:元素的背景是内容.内边距和边框区的背景 2.也就是说背景颜色,background-color:这些会填充内边距和边框border, 而不会填充外边框margin的 ...