线程与并发
1. 线程的基础理论
1.1 用自己的理解说说线程是什么?
操作系统在为每一个运行程序创建一个进程(进程简单理解就是程序实例),它是一个线程的容器,看到一个形象的比喻:如果把操作系统看做一个工厂,进程好比工厂的车间,它代表CPU所能执行的单个任务,一个车间里,又有很多工人,他们协同完成同一个任务。线程好比车间里的工人,一个进程可以包括多个线程。
1.2 使用Java代码展示简单地实例
按照传统的意义上来说,创建一个线程的方式有两种
继承 Thread 类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20* 继承Thread类,作为线程的实现类
*/
public class MyThread extends Thread{
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + "运行,i = " + i) ;
}
}
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A ") ; // 实例化对象
MyThread mt2 = new MyThread("线程B ") ; // 实例化对象
mt1.start() ; // 调用线程主体
mt2.start() ; // 调用线程主体
}
}执行结果
实现 Runnable 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23/**
* 实现Runnable接口,作为线程的实现类
*/
public class MyThread implements Runnable{
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public void run(){ // 覆写run()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + "运行,i = " + i) ;
}
}
public static void main(String[] args) {
MyThread mt1 = new MyThread("线程A ") ; // 实例化对象
MyThread mt2 = new MyThread("线程B ") ; // 实例化对象
Thread t1 = new Thread(mt1) ; // 实例化Thread类对象
Thread t2 = new Thread(mt2) ; // 实例化Thread类对象
t1.start() ; // 启动多线程
t2.start() ; // 启动多线程
}
}执行结果
实现 Callable 接口
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/**
* 实现Callable接口,作为线程的实现类
*/
public class MyThread implements Callable<String> {
private String name ; // 表示线程的名称
public MyThread(String name){
this.name = name ; // 通过构造方法配置name属性
}
public String call(){ // 覆写call()方法,作为线程 的操作主体
for(int i=0;i<10;i++){
System.out.println(name + "运行,i = " + i) ;
}
return "我是" + name + "的返回结果";
}
public static void main(String[] args) throws Exception {
FutureTask<String> f1 = new FutureTask<>(new MyThread("线程A ")) ; // 实例化对象
FutureTask<String> f2 = new FutureTask<>(new MyThread("线程B ")) ; // 实例化对象
// 提交异步任务
Thread t1 = new Thread(f1);
Thread t2 = new Thread(f2);
t1.start() ; // 调用线程主体
t2.start() ; // 调用线程主体
System.out.println(f1.get());
System.out.println(f2.get());
}
}执行结果
PS:有了Thread和Runnable为什么还需要Callable接口呢,因为上面两种方式都存在一种局限:在执行完任务之后无法获取执行结果。
这种方式严格意义上来说不是一种创建线程的方式,它依赖的是FutureTask(一个继承Runnable接口的接口),在Runnable接口上进行封装了返回结果。