Fork me on GitHub

多线程的几种实现方式

  线程是Java中的一个重要学习内容,有一段时间没用到,最近重温了一下。写点东西记录一下。

什么是线程?

线程是指程序在执行过程中,能够执行程序程序代码的一个执行单元。在Java语言中,线程有四种状态:运行、就绪、挂起和结束。

为什么要使用多线程

  • 使用多哦线程可以减少程序的相应时间。
  • 多CPU或多核计算机本身就具有执行多线程的能力。
  • 与进程相比,线程的创建和切换开销更小。
  • 使用多线程能简化程序的结构,使程序便于维护和理解。一个非常复杂的进程可以分成多个线程来执行。

基本的线程机制

在使用线程时,CPU将轮流给每个任务分配其占用时间。每个任务都觉得自己在一直占用着CPU,但事实上CPU时间是划分成片段分配给所有的任务。线程可以使你从这个层次抽身出来。
注意:当系统使用时间切片机制时,CPU轮流给每个任务分配时间,例如Windows(线程优先级和时间片轮转调度)操作系统。但有些操作系统采用FIFO模型,除非有高优先级的线程被唤醒,否则当前线程将一直运行,直至阻塞或终止。

如何实现Java多线程

继承Thread类,重写run()方法

Thread 本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,
启动线程的唯一方法就是通过Thread类的start()方法。start()方法是一个native(本地)方法,它将启动一个新线程,并执行一个run()方法(Thread中提供的run()方法是一个空方法)。
这种方式通过自定义直接继承Thread,并重写run()方法,就可以启动新线程并执行自己定义的run()方法。
调用start()方法后并不是立即执行多线程代码,而是使得该线程变成可运行态,什么时候运行多线程是由CPU调度决定的

1
2
3
4
5
6
7
8
9
10
11
class MyThread extends Thread{
public void run(){
System.out.println("Thread body");
}
}
public class Test{
public static void main(String[] args){
MyThread thread=new MyThread();
thread.run();
}
}

实现Runnable接口,并实现该接口的run()方法

主要步骤:
1) 自定义类并实现Runnable接口,并实现run()方法。
2) 创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread对象。
3) 调用Thread的start()方法。

1
2
3
4
5
6
7
8
9
10
11
12
class MyThread implements Runnable{
public void run(){
System.out.println("Thread body");
}
}
public class Test{
public static void main(String[] args){
MyThread thread=new MyThread();
Thread t=new Thread(thread);
t.start();
}
}

以上两种是实现多线程最常用的方法。
其实不管是通过继承Thread类还是通过使用Runnable接口来实现多线程的方法,最终还是通过Thread的对象的API来控制线程的。

实现Callable接口,重写call()方法

Callable接口实际上是属于Executor框架的功能类,Callable接口与Runnable接口的功能类类似,但提供了比Runnable更强大的功能,主要表现在以下三点:
1)Callable可以在任务结束后提供一个返回值,Runnable无法提供这个功能。
2)Callable中的call()方法可以抛出异常,而Runnable的run()方法无法抛出异常。
3)运行Callable可以拿到一个Future对象,Future对象表示异步计算的结果,可以使用Future来监视目标线程调用call()方法的情况,当调用Future的get()方法以获取结果时,当前线程就会阻塞,直到call()方法结束返回结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CallableAndFuture{
//创建线程类
public static class CallableTest implements Callable<String>{
@Override
public String call() throws Exception {
return "欢迎来到我的博客!";
}
}

public static void main(String[] args){
ExecutorService threadPool= Executors.newSingleThreadExecutor();
//启动线程
Future<String> future=threadPool.submit(new CallableTest());
try {
System.out.println("waiting thread to finish");
//等待线程结束,并获取返回结果
System.out.println(future.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}

上述程序的输出结果为:

以上3中方式中,前两种方式线程执行完后都没有返回值,只有最后一种带有返回值的,但是当需要使用多线程时,一般最好是使用实现Runnable接口的方式。
因为Thread类定义的多中方法可以被派生类使用或者重写。但是只有run()方法是必须被重写的,在run()方法中实现了这个线程的主要功能。

本文标题:多线程的几种实现方式

文章作者:Jeremy

发布时间:2018年01月02日 - 21:01

最后更新:2018年04月19日 - 17:04

原始链接:http://yoursite.com/2018/01/02/多线程的几种实现方式/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢您的阅读-------------
你的支持是我最大的动力