
在各家的面试中中,不管是校招还是社招都会出现这样的问题:线程创建的方式。正常来说你要回答三种:继承Thread类(不推崇)不要问为什么,因为Java只支持单继承的,实现Runnable接口(推崇)Java在接口实现上可以实现无数个接口,通过线程池(推崇)线程池,企业级项目必用 下面就让我来展示一下Java中线程创建的三种方式的代码实现:
## 继承Thread类 ## ```java public class Match1 { public static void main(String[] args) { // 创建一个新的线程 Runner liuxiang = new Runner(); //设置线程名称 liuxiang.setName("刘翔"); //启动线程 Runner dingjie = new Runner(); dingjie.setName("丁杰"); Runner op = new Runner(); op.setName("路飞"); liuxiang.start(); dingjie.start(); op.start(); } } /** * */ class Runner extends Thread { @Override public void run() { Integer speed = new Random().nextInt(100); for (int i = 1; i <= 100; i++) { try { // 将当前线程休眠一秒 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //this.getName()打印当前线程的名字 Console.log(this.getName() + "已前进" + (i * speed) + "米(" + speed + "米/秒)"); } } } ``` ## 实现Runnable接口 ## ```java public class Match2 { public static void main(String[] args) { Thread liuxiang = new Thread(new Runner2()); liuxiang.setName("刘翔"); Thread dingjie = new Thread(new Runner2()); dingjie.setName("丁杰"); Thread op = new Thread(new Runner2()); op.setName("路飞"); liuxiang.start(); dingjie.start(); op.start(); } } class Runner2 implements Runnable { /** * When an object implementing interfaceRunnable
is used
* to create a thread, starting the thread causes the object's
* run
method to be called in that separately executing
* thread.
*
* The general contract of the method run
is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
Integer speed = new Random().nextInt(100);
for (int i = 1; i <= 100; i++) {
try {
// 将当前线程休眠一秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Thread.currentThread():用于获取当前执行的线程,在Runnable中是无法使用this来获取当前的线程的对象的
Console.log(Thread.currentThread().getName() + "已前进" + (i * speed) + "米(" + speed + "米/秒)");
}
}
}
```
## 线程池 ##
```java
public class Match3 {
public static void main(String[] args) {
//创建一个线程池,里面创建了3个固定的线程,Executors为调度器
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 实例化Callable对象
Runner3 liuxiang = new Runner3();
liuxiang.setName("刘翔");
Runner3 dingjie = new Runner3();
dingjie.setName("丁杰");
Runner3 lufei = new Runner3();
lufei.setName("路飞");
Runner3 temp = new Runner3();
// 将对象扔到线程池里面,线程池自动分配一个线程
// Future用于接受线程内部call方法的返回值
Future liuxiangFuture = executorService.submit(liuxiang);
Future dingjieFutrue = executorService.submit(dingjie);
Future lufeiFutrue = executorService.submit(lufei);
Future tempFutrue = executorService.submit(temp);
try {
// 阻塞五秒
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 关闭线程池,释放所有资源
executorService.shutdown();
try {
Console.log("刘翔已经跑了" + liuxiangFuture.get() + "米");
Console.log("丁杰已经跑了" + dingjieFutrue.get() + "米");
Console.log("路飞已经跑了" + lufeiFutrue.get() + "米");
Console.log("temp已经跑了" + tempFutrue.get() + "米");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
/**
* 泛型的内容为call()方法的返回值
*/
class Runner3 implements Callable {
private String name;
public void setName(String name) {
this.name = name;
}
/**
* Computes a result, or throws an exception if unable to do so.
* 实现Callable接口,允许线程返回值以及异常
*
* @return computed result
*
* @throws Exception
* if unable to compute a result
*/
@Override
public Integer call() throws Exception {
Integer speed = new Random().nextInt(100);
//总共奔跑的距离
Integer distinct = 0;
for (int i = 1; i <= 100; i++) {
Thread.sleep(10);
distinct = i * speed;
Console.log(this.name + "已前进" + distinct + "米(" + speed + "米/秒)");
}
return distinct;
}
}
```
下面来看一下三中创建方式的优缺点:
继承Thread类 | 实现Runnable接口 | 利用线程池 | |
---|---|---|---|
优点 | 1.编程简单; 2.执行效率高 | 1.面向接口编程 2.执行效率高 | 1.容器管理线程 2.允许返回值与异常 |
缺点 | 1.单继承 2.无法对线程进行有效的控制 | 1.无法对线程组有效控制; 2.没有返回值 | 1.执行效率相对低; 2.编程麻烦 |
使用场景 | 不推荐使用 | 简单的多线程程序 | 企业级应用,推荐使用 |