继承Thread类

通过继承Thread类,并重写它的run方法,我们就可以创建一个线程,然后通过start方法开启线程(开启线程前的代码会先执行完)。不要使用run方法,因为使用run方法会把线程当作普通方法使用,就不是多线程运行了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @author LeDao
* @company
* @create 2021-07-09 22:45
*/
public class MyThread extends Thread{

@Override
public void run() {
System.out.println("线程运行");
}

public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
}
}

实现 Runnable接口

通过实现Runnable,并实现run方法,也可以创建一个线程,这种方法比继承Thread类好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @author LeDao
* @company
* @create 2021-07-09 22:45
*/
public class MyThread implements Runnable{

@Override
public void run() {
System.out.println("运行线程");
}

public static void main(String[] args) {
Thread thread = new Thread(new MyThread());
thread.start();
}
}

实现 Callable 接口

实现Callable接口,并结合Future实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
* @author LeDao
* @company
* @create 2021-07-09 22:45
*/
public class MyThread implements Callable {

@Override
public String call() {
return "1";
}

public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask task = new FutureTask(new MyThread());
new Thread(task).start();
String result = (String) task.get();
System.out.println(result);
}
}

通过线程池创建线程

用JDK自带的Executors来创建线程池对象(推荐使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package thread;

import cn.hutool.core.thread.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
* @author LeDao
* @company
* @create 2022-04-25 13:44
*/
public class ThreadTest3 implements Runnable {

@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("玩游戏---" + i);
}
}

public static void main(String[] args) {
//获取系统处理器个数,作为线程池数量
int nThreads = Runtime.getRuntime().availableProcessors();
System.out.println(nThreads);
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNamePrefix("demo-pool-%d").build();
ExecutorService executorService = new ThreadPoolExecutor(nThreads,
200,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1024),
namedThreadFactory,
new ThreadPoolExecutor.AbortPolicy());
executorService.execute(new ThreadTest3());
for (int i = 0; i < 1000; i++) {
System.out.println("学习---" + i);
}
executorService.shutdown();
}
}

上面代码的ThreadPoolExecutor构造方法的一些参数说明如下(按顺序):

  1. corePoolSize - 即使空闲时仍保留在池中的线程数,除非设置 allowCoreThreadTimeOut
  2. maximumPoolSize - 池中允许的最大线程数
  3. keepAliveTime - 当线程数大于内核时,这是多余的空闲线程在终止前等待新任务的最大时间
  4. unit - keepAliveTime参数的时间单位
  5. workQueue - 用于在执行任务之前使用的队列。 这个队列将仅保存execute方法提交的Runnable任务
  6. threadFactory - 执行程序创建新线程时使用的工厂
  7. handler - 执行被阻止时使用的处理程序,因为达到线程限制和队列容量

PS.

来源:面试官问我:创建线程有几种方式?我笑了 - SegmentFault 思否

更多线程池的使用查看:线程池的7种创建方式,强烈推荐你用它… - Java中文社群 - 博客园 (cnblogs.com)