从Java创建线程入门多线程

本文是Java多线程系列的第一篇文章,关于线程的基础知识这里不多介绍,在我之前的文章中就已经介绍过了,不熟悉什么是线程的同学可以先去看一下。操作系统-进程与线程

从最老生常谈的Java创建线程方式谈起

稍微了解过一点Java多线程编程的朋友一定知道,Java创建线程的方式一般有三种:重写Thread类、实现Runnable和实现Callable接口,当然线程池也算是创建线程的一种方式,但那就扯远了,我们暂时从这三种方式聊起。

重写Thread类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CreateThreadTest {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
}

class MyThread extends Thread {
@Override
public void run() {
System.out.println("do something here...");
}
}

很简单的方式,重写Thread类的demo上面已给出。

实现Runnable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CreateThreadTest {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
}
}

class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("do something here...");
}
}

同样很简单,实现Runnable接口后将MyRunnable对象传给Thread类。

实现Callable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CreateThreadTest {
public static void main(String[] args) {
FutureTask<Boolean> result = new FutureTask<>(new MyCallable());
Thread t = new Thread(result);
t.start();
try {
System.out.println(result.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}

class MyCallable implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
System.out.println("do something here...");
return true;
}
}

实现Callable接口这种方式与实现Runnable接口的不同之处在于多了一个返回值。

start()和run()到底有什么区别

首先需要明确的是,start()是一个native方法,该方法会启动一个线程,线程执行run()方法里的内容。与直接执行run()方法不同的是,start()会启动一个新的线程,这个线程与主线程并发执行。如果直接执行线程的run()方法就不会启动新的线程,相当于执行了一个普通方法。

关于run()方法的细节

run()方法作为创建线程的核心,我们这里就来扒一扒源码。

首先是Thread类的run()方法,代码如下:

1
2
3
4
5
6
7
8
private Runnable target;

@Override
public void run() {
if (target != null) {
target.run();
}
}

很显然,Thread类中的run()方法就是调用Runnable对象的run()方法,我们再看一下Runnable接口的源码。

1
2
3
4
@FunctionalInterface
public interface Runnable {
public abstract void run();
}

Runnable接口很简单,就是一个run()抽象方法。在Runnable接口上有个@FunctionalInterface注解,表明可以实现函数式编程。

如果既继承了Thread类又实现了Runnable接口呢?

有没有想过当一个线程既继承了Thread类又实现了Runnable接口会执行哪个run()方法?

1
2
3
4
5
6
7
8
9
10
11
public class CreateThreadTest {
public static void main(String[] args) {
Thread t = new Thread(() -> System.out.println("Runnable method")) {
@Override
public void run() {
System.out.println("Thread method");
}
};
t.start();
}
}

大家觉得上面的代码会怎么执行?答案是执行匿名内部类中的方法,也就是打印Thread method。回顾一下之前分析的源码就不难知道,在Thread中执行的是target对象的run()方法,而这里我们在匿名内部类中重写了run()方法,与原来的父类run()方法已经没有关系了,自然也不会运行target对象的run()方法。

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2015-2022 sky-ng
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信