三种创建线程的方式
# 以前的 Java 代码是单线程执行的吗?
在学习多线程之前,我们写的一个包含main
方法的一个Java
程序是单线程的么?
三线程
答案肯定不是了,以前一个 JAVA 程序也是有 3 个线程同时执行的。
PS
异常线程会影响主线程的执行。
# 三种创建线程的方式
- 继承
Thread
类 - 实现
Runnable
接口 - 实现
Callable
接口
# Thread 类
- 自定义线程类继承
Thread
- 重写
run()
方法,编写线程执行体 - 创建线程对象,调用
start()
方法启动线程 - 线程不一定立即执行,看 CPU 调度
package com.thread;
// 继承Thread类
public class TestThread1 extends Thread {
@Override
public void run() {
// 重写run() 方法
// 线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码: " + i);
}
}
public static void main(String[] args) {
// 创建一个线程对象,调用start()方法
TestThread1 testThread1 = new TestThread1();
// 调用start() 开启线程
testThread1.start();
// main 主线程
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程: " + i);
}
}
}
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
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
交替执行,结果还是看 CPU,每次结果可能都不一样
我在看代码: 0
我在看代码: 1
我在看代码: 2
我在看代码: 3
我在看代码: 4
我在看代码: 5
我在看代码: 6
我在看代码: 7
我在看代码: 8
我在看代码: 9
我在看代码: 10
我在学习多线程: 0
我在看代码: 11
我在看代码: 12
我在学习多线程: 1
我在学习多线程: 2
我在看代码: 13
我在看代码: 14
我在看代码: 15
我在看代码: 16
我在看代码: 17
我在看代码: 18
我在看代码: 19
我在学习多线程: 3
我在学习多线程: 4
我在学习多线程: 5
# ... 后面都是我在学习多线程 数字一次往后到199 主要为了看交替执行
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
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
调整 2 个线程的循环次数进行调整测试
# 案例:多线程下载图片
需要一个 apache 的包
将commons-io-2.11.0.jar
包放到com
包下的lib
包里,右键lib
包添加到项目库即可使用。
package com.thread;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.URL;
// 实现多线程同步下载图片
public class TestThread2 extends Thread {
private String url; // 网络图片地址
private String name; // 保存的文件名
public TestThread2(String url, String name) {
this.url = url;
this.name = name;
}
// 下载图片的线程的执行体
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名: " + name);
}
public static void main(String[] args) {
// 图片可以自己找了试验
TestThread2 t1 = new TestThread2("第1张网图.png", "1.png");
TestThread2 t2 = new TestThread2("第2张网图.png", "2.png");
TestThread2 t3 = new TestThread2("第3张网图.png", "3.png");
// 并不是按照线程顺序来执行的,每次结果都不一定相同
// 同时下载3张图片
t1.start();
t2.start();
t3.start();
}
}
// 下载器
class WebDownloader {
// 下载方法
public void downloader(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO异常, downloader方法出现问题");
}
}
}
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
49
50
51
52
53
54
55
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
49
50
51
52
53
54
55
# 实现 Runnable 接口
- 定义
MyRunnable
类实现Runnable
接口 - 实现
run()
方法,编写线程执行体 - 创建线程对象,调用
start()
方法启动线程
提示
推荐使用Runnable
对象,因为 Java 单继承的局限性
package com.thread;
// 实现Runnable接口,重写run方法,调用start
public class TestThread3 implements Runnable{
@Override
public void run() {
// 重写run() 方法
// 线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在看代码: " + i);
}
}
public static void main(String[] args) {
// 创建runnable接口的实现类对象
TestThread3 testThread3 = new TestThread3();
// 创建一个线程对象,通过线程对象来开启我们的线程,代理
// Thread thread = new Thread(testThread3);
// thread.start();
// 简写
new Thread(testThread3).start();
// main 主线程
for (int i = 0; i < 200; i++) {
System.out.println("我在学习多线程: " + i);
}
}
}
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
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
# 实现 Callable 接口(了解即可)
- 实现
Callable
接口,需要返回值类型 - 重写
call
方法,需要抛出异常 - 创建目标对象
- 创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行:
Future<Boolean> result1 = ser.submit(t1);
- 获取结果:
boolean r1 = result1.get();
- 关闭服务:
ser.shutdownNow()
package com.thread;
import java.util.concurrent.*;
public class TestCallable implements Callable<Boolean> {
private String url;
private String name;
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下载了文件名: " + name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable c1 = new TestCallable("网图1.png", "1.png");
TestCallable c2 = new TestCallable("网图2.png", "2.png");
TestCallable c3 = new TestCallable("网图3.png", "3.png");
// 创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
// 提交执行
Future<Boolean> r1 = ser.submit(c1);
Future<Boolean> r2 = ser.submit(c2);
Future<Boolean> r3 = ser.submit(c3);
// 获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
// 关闭服务
ser.shutdownNow();
}
}
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
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
# 小结
- 继承 Thread 类
- 子类继承 Thread 类具备多线程能力
- 启动线程:
子类对象.start()
- 不建议使用:避免 OOP 单继承局限性
- 实现
Runnable
接口- 实现接口
Runnable
具有多线程能力 - 启动线程:传入目标对象 +
Thread
对象.start() - 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
- 实现接口
编辑 (opens new window)
上次更新: 2022/02/08, 22:58:48