Java 多线程的实现方式有:继承Thread类,实现Runnable接口。另外,使用内部类实现,Callable、Future组合实现(有返回值),使用线程池,定时器以及Java 8中Lambda表达式实现的方式,实际是对前两种方式的变形。

一、继承Thread类

继承Thread类,重写run()方法,Thread类也是Runnable接口的一个实现,启动线程的唯一方法是start()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Thread;

public class ThreadDemo extends Thread {

@Override
public void run() {
System.out.println("当前线程为:" + Thread.currentThread().getName());
}

public static void main(String[] args) {
ThreadDemo demo1 = new ThreadDemo();
ThreadDemo demo2 = new ThreadDemo();

demo1.start();
demo2.start();

}

}

程序运行结果为:

1
2
当前线程为:Thread-0
当前线程为:Thread-1

二、实现Runnable接口

实现Runnable接口,重写run()方法,为了启动Runnable实例,需要实例化一个Thread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package Thread;

public class RunnableDemo implements Runnable {

public static void main(String[] args) {

RunnableDemo demo = new RunnableDemo();

Thread thread1 = new Thread(demo);
Thread thread2 = new Thread(demo);

thread1.start();
thread2.start();
}

@Override
public void run() {
System.out.println("当前线程为:" + Thread.currentThread().getName());
}

}

程序运行结果为:

1
2
当前线程为:Thread-1
当前线程为:Thread-0

三、使用内部类实现

如果一个线程只执行一次,使用上述两种方法就显得有些麻烦,使用内部类正好解决这种情况。

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
package Thread;

public class InnerThreadDemo {

public static void main(String[] args) {

// 继承Thread类
new Thread() {

@Override
public void run() {
System.out.println("继承Thread线程");
}

}.start();

// 实现Runnable接口
new Thread(new Runnable() {

@Override
public void run() {
System.out.println("实现Runnable线程");
}

}).start();

}

}

程序运行结果为:

1
2
继承Thread线程
实现Runnable线程

四、使用Callable、Future组合

实现Runnable、继承Thread类是没有返回结果的,此时需要用Callable和Future组合实现有返回值的线程。
1、使用匿名内部类实现Callable接口,重写call()方法。
2、实例化一个FutureTask,指定Callable实例,作为线程任务。
3、使用Thread开启线程任务。
4、使用FutureTask的get()方法获取线程的执行结果。

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
package Thread;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class CallableDemo {

static Callable<Integer> num = new Callable<Integer>() {

@Override
public Integer call() throws Exception {
return 1;
}

};

static Callable<String> str = new Callable<String>() {

@Override
public String call() throws Exception {
return "str";
}

};

public static void main(String[] args) throws Exception {
FutureTask<Integer> number = new FutureTask<Integer>(num);
FutureTask<String> sub = new FutureTask<String>(str);

new Thread(number).start();
new Thread(sub).start();

System.out.println("Integer执行结果为:" + number.get());
System.out.println("String执行结果为:" + sub.get());
}

}

程序输出结果为:

1
2
Integer执行结果为:1
String执行结果为:str

注意:get()方法是阻塞的,如果线程没有返回值,则get()方法一直等待

五、使用线程池

Java通过Executors提供了四种线程池,分别为:
1、newSingleThreadExecutor: 初始化的线程池中只有一个线程,唯一的线程可以保证所有提交的任务按照指定顺序执行。
2、newFixedThreadPool:创建一个固定数量线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3、newScheduledThreadPool:创建一个固定数量线程池,支持定时及周期性任务执行。
4、newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
使用线程池:

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
41
42
43
44
45
46
47
48
package Thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class ExecutorDemo {

static Callable<Integer> num = new Callable<Integer>() {

@Override
public Integer call() throws Exception {
return 1;
}

};

static Callable<String> str = new Callable<String>() {

@Override
public String call() throws Exception {
return "str";
}

};

public static void main(String[] args) throws Exception {
FutureTask<Integer> number = new FutureTask<Integer>(num);
FutureTask<String> sub = new FutureTask<String>(str);
ExecutorService threadPool = Executors.newFixedThreadPool(2);

try {
// 给线程中加入任务
threadPool.execute(number);
threadPool.execute(sub);
} finally {
// 关闭线程池
threadPool.shutdown();
}


System.out.println("Integer执行结果为:" + number.get());
System.out.println("String执行结果为:" + sub.get());

}

}

程序执行结果为:

1
2
Integer执行结果为:1
String执行结果为:str

推荐大家阅读:(https://www.cnblogs.com/dolphin0520/p/3932921.html)

六、使用定时器

定时计划任务功能在Java中主要使用的就是Timer对象,它在内部使用多线程的方式进行处理
1、实例化Timer,执行schedule()方法。
2、实例化TimerTask,重写run()方法

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
package Thread;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {

public static void main(String[] args) {
Timer timer = new Timer();

// 每隔5秒执行
timer.schedule(new TimerTask() {

@Override
public void run() {
System.out.println("每隔5秒执行一次");
}

}, new Date(), 5000);

// 固定时间执行
timer.schedule(new TimerTask() {

@Override
public void run() {
System.out.println("固定时间执行");
}

}, new Date());

}

}

程序运行结果为:

1
2
3
4
5
6
7
8
每隔5秒执行一次
固定时间执行
每隔5秒执行一次
每隔5秒执行一次
每隔5秒执行一次
每隔5秒执行一次
每隔5秒执行一次
...

schedule()还有好多重载方法,可以查看相应的API进行了解。

七、使用Lambda表达式实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package Thread;

public class LambedDemo {

public static void main(String[] args) {

System.out.println("主线程为:" + Thread.currentThread().getName());

Runnable a = () -> {
System.out.println("Runnable线程为:" + Thread.currentThread().getName());
};

new Thread(a).start();

new Thread(() -> System.out.println("Thread线程为:" + Thread.currentThread().getName())).start();

}

}

程序运行结果为:

1
2
3
主线程为:main
Runnable线程为:Thread-0
Thread线程为:Thread-1