详解多线程启动涉及的知识点

简介: 详解多线程启动涉及的知识点

Thread类

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易实现资源共享。实现Runnable接口比继承Thread类所具有的优势:

  • 适合多个相同的程序代码的线程去处理同一个资源
  • 可以避免java中的单继承的限制
  • 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
//继承 Thread
Thread1 mTh1=new Thread1("A");
Thread1 mTh2=new Thread1("B");
mTh1.start();
mTh2.start();

Runnable接口

// 先看一下java.lang.Runnable,它是一个接口,在它里面只声明了一个run()方法:
// 由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。
public interface Runnable {
    public abstract void run();
}
//实现Runnable接口
Thread2 mTh = new Thread2();
new Thread(mTh, "C").start();//同一个mTh,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常   
new Thread(mTh, "D").start();
new Thread(mTh, "E").start();

这两种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。

而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。

Callable接口

Callable接口位于java.util.concurrent包下,在它里面也只声明了一个方法,只不过这个方法叫做call()

public interface Callable<V> {
    V call() throws Exception;
}

可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。Callable接口可以看作是Runnable接口的补充,call方法带有返回值,并且可以抛出异常。

FutureTask类

如何获取Callable的返回结果呢?一般是通过FutureTask这个中间媒介来实现的。整体的流程是这样的:

  • 把Callable实例当作参数,生成一个FutureTask的对象
  • 然后把这个对象当作一个Runnable,作为参数另起线程。

由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。下面以Thread包装线程方式启动来说明一下。

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class Demo {
    public static void main(String[] args) throws Exception {
        Callable<Integer> call = new Callable<Integer>() {
            public Integer call() throws Exception {
                System.out.println("计算线程正在计算结果...");
                Thread.sleep(3000);
                return 1;
            }
        };
        FutureTask<Integer> task = new FutureTask<>(call);
        Thread thread = new Thread(task);
        thread.start();
        System.out.println("main线程干点别的...");
        Integer result = task.get();
        System.out.println("从计算线程拿到的结果为:" + result);
    }
}

Future接口

FutureTask继承体系中的核心接口是Future。

Future的核心思想是:一个方法,计算过程可能非常耗时,等待方法返回,显然不明智。可以在调用方法的时候,立马返回一个Future,可以通过Future这个数据结构去控制方法f的计算过程。这里的控制包括:

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);//还没计算完,可以取消计算过程
    boolean isCancelled();///判断计算是否被取消
    boolean isDone();//判断是否计算完
    V get() throws InterruptedException, ExecutionException;
    //获取计算结果(如果还没计算完,也是必须等待的)
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

也就是说Future提供了三种功能:

  • 判断任务是否完成;
  • 能够中断任务;
  • 能够获取任务执行结果。

实现Runnable接口和Callable接口的区别

如果想让线程池执行任务的话需要实现的Runnable接口或Callable接口。

Runnable接口或Callable接口实现类都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行。两者的区别在于 Runnable 接口不会返回结果但是 Callable 接口可以返回结果。

备注:工具类 Executors 可以实现 Runnable 对象和 Callable 对象之间的相互转换。
Executors.callable(Runnable task)也就是说Future提供了三种功能:

  • 判断任务是否完成;
  • 能够中断任务;
  • 能够获取任务执行结果。Executors.callable(Runnable task,Object resule )。
相关文章
|
2月前
|
算法 安全 调度
多线程如何工作,工作原理是什么
多线程如何工作,工作原理是什么
|
7天前
|
Java
[并发编程基础] Java线程的创建方式
[并发编程基础] Java线程的创建方式
|
8月前
线程基础知识点
本章讲解了线程的相关知识
29 0
|
9月前
|
安全 Linux 调度
Linux线程管理:深入探索多线程编程的原理与实践
在Linux操作系统中,线程是轻量级的执行单元,多线程编程允许程序在同一进程内执行多个并发任务,提高程序性能和资源利用率。本文将深入探讨Linux线程管理的相关知识,包括线程的创建、终止与调度,以及线程间通信的实现,旨在帮助读者深入理解多线程编程的原理与实践。
174 1
|
12月前
|
Java
高并发编程-自定义简易的线程池(2),体会原理
高并发编程-自定义简易的线程池(2),体会原理
49 0
|
存储 设计模式 Java
74. 对多线程熟悉吗,来谈谈线程池的好处?
74. 对多线程熟悉吗,来谈谈线程池的好处?
98 0
|
Java API 调度
java多线程之概念和3种创建方式(详解)
进程:一个执行的应用程序 线程:一个应用程序内的具体执行不同模块
103 0
java多线程之概念和3种创建方式(详解)
java线程的三种创建方式详细分析(全)
目录前言1. 继承Thread类2. 实现Runnable 接口3. 通过Callable和Future创建线程4. 总结 前言 关于线程这部分内容讲的比较多,可看我之前的文章 【操作系统】线程与进程的深入剖析(全) 【操作系统】守护线程和守护进程的区别 对于线程Thread的分析 也可看我之前的文章 java之Thread类详细分析(全) java之Thread类实战模板(全) 多线程中run()和start()的异同详细分析(全) 对于创建方式的汇总以及方式 可看我这篇文章的总结对比 1. 继承
java线程的三种创建方式详细分析(全)
【多线程】面试官:如何利用线程工具,防止多线程同时操作一个资源?
通过前面的学习,知道了线程的利与弊,正确的使用多线程,会尽最大的可能去压榨我们系统的资源,从而提高效率,但是如果不合理使用线程,可能会造成副作用,给系统带来更大的压力,进一步的思考,如何才能防止多线程操作一个资源?
|
Java API Spring
java并发原理实战(4) -- 线程的创建方式
java并发原理实战(4) -- 线程的创建方式
101 0
java并发原理实战(4) -- 线程的创建方式