整体大图
JAVA多线程学习是javaer的一大难关,博主也在其中绕了又绕,看了又看,看完又忘,忘了再看,看了再忘,如此反复,不得其要,所以决定写这个多线程学习的系列博客,刨根问底,习得精髓。
构思了一下,画了下面的XMIND图,整个系列化会按照这个图来写,如果有更好的图结构,欢迎大家指点。
线程的基础知识
关于线程和进程的区别我就不多复述了,给大家贴一个百度链接
https://baike.baidu.com/item/%E7%BA%BF%E7%A8%8B/103101?fr=aladdin
创建线程的几种方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable 接口
前两条都是大家熟知的线程创建方式,但是第三条可能不太熟悉,看下javadoc
package java.util.concurrent;
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
*
* <p>The {@code Callable} interface is similar to {@link
* java.lang.Runnable}, in that both are designed for classes whose
* instances are potentially executed by another thread. A
* {@code Runnable}, however, does not return a result and cannot
* throw a checked exception.
*
* <p>The {@link Executors} class contains utility methods to
* convert from other common forms to {@code Callable} classes.
*
* @see Executor
* @since 1.5
* @author Doug Lea
* @param <V> the result type of method {@code call}
*/
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
A task that returns a result and may throw an exception.
其实第一句就说明了Callable和其他实现方式的不同之处,Callable是可以带有返回值的并且可能会抛出异常
。
如同其他实现方式一样,Callable接口也有一个执行的方法那就是call
方法
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
计算结果或者抛出一个异常,其中V代表要返回结果的类型。
使用Callable来创建线程
使用thread和runnable创建线程这里就不多写了,主要看下callable是如何创建线程的
- 实现Callable接口 返回类型为String
public class Call implements Callable<String>{
@Override
public String call() throws Exception {
return "这是一个callable线程执行的结果";
}
}
- 使用FutureTask包裹Callable实现
Call call = new Call();
FutureTask<String> task = new FutureTask<>(call);
- 使用Thread类包装FutureTask,并且启动线程
Thread thread = new Thread(task);
thread.start();
- 获取执行结果 (使用FuntureTask::get方法获取)
String s = task.get();
System.out.println(s);
暂且不管FutureTask
类是个什么鬼,在后续篇章会写到。
Callable接口和Runnable接口的区别
Callable接口和Runnable接口最大的区别其实在上面已经写到了
其他实现方式的不同之处,Callable是可以带有返回值的并且可能会抛出异常
- Callable带有返回值
- Callable可以抛出异常
再看下call方法
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
call
方法会返回泛型V
,并且会throws Exception
再看下Runable的run方法
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
没有返回值,并且不会抛出异常,也就是说即使run内部有异常,那么也不会被catch到
总结
-
创建线程的方式有三种: 1. 继承Thread类,重写run方法 2. 实现Runnable接口,重写run方法 3. 实现Callable接口,实现call方法
-
Callable和Runnable接口的区别 1. callable接口有返回值 2. callable接口可抛出异常