进程、线程
进程(Process)是计算机中程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
指在系统中正在运行的一个应用程序,程序一旦运行就是进程
资源分配的最小单位
线程(Thread)是操作系统能够进程元算调度的最小单位。它别包含在进程之中,是进程中的实际运作单位,一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。
程序执行的最小单位
一个进程至少有一个线程,通常在一个进程中可以包含若干个线程,不然就没有了存在的意义,线程就是cpu调度和执行的单位。
真正的多线程是指有多个cpu(即多核),如果是模拟出来的多线程(即在有一个cpu的情况下),在同一个时间点,cpu只能执行一个,因为计算机处理是纳秒,所以切换的会很快,就会有同时执行的错觉。
多线程实现
继承Thread
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
41package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
/**
* 实现多线程-继承Thread
*
* @author _running
* @since 2022-05-08
*/
public class StudyThread extends Thread {
/**
* 重写run()方法
*/
public void run() {
for (int i = 0; i < 24; i++) {
Console.log(StrUtil.format("继承Thread,{}:正在执行中!", Thread.currentThread().getName()));
}
}
public static void main(String[] args) {
// 创建线程对象
StudyThread st1 = new StudyThread();
// 设置线程名称
st1.setName("Tony");
// 开启线程
st1.start();
// 创建线程对象
StudyThread st2 = new StudyThread();
// 设置线程名称
st2.setName("Tom");
// 开启线程
st2.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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
/**
* 实现多线程-实现Runnable
*
* @author _running
* @since 2022-05-08
*/
public class StudyRunnable implements Runnable {
/**
* 重写run()方法
*/
public void run() {
for (int i = 0; i < 24; i++) {
Console.log(StrUtil.format("实现Runnable:{},正在执行中!", Thread.currentThread().getName()));
}
}
public static void main(String[] args) {
// 创建类对象
StudyRunnable sr1 = new StudyRunnable();
// 创建线程对象
Thread t1 = new Thread(sr1, "Tony");
// 开启线程
t1.start();
// 创建类对象
StudyRunnable sr2 = new StudyRunnable();
// 创建线程对象
Thread t2 = new Thread(sr2, "Tom");
// 开启线程
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
/**
* 实现多线程-实现Callable
*
* @author _running
* @since 2022-05-08
*/
public class StudyCallable implements Callable<Boolean> {
public Boolean call() throws Exception {
for (int i = 0; i < 24; i++) {
Console.log(StrUtil.format("实现Callable:{},正在执行中!", Thread.currentThread().getName()));
}
return Boolean.TRUE;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 创建执行服务
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 创建类对象
StudyCallable sc1 = new StudyCallable();
// 创建类对象
StudyCallable sc2 = new StudyCallable();
// 提交有结果的执行
Future<Boolean> submit1 = executorService.submit(sc1);
// 提交有结果的执行
Future<Boolean> submit2 = executorService.submit(sc2);
// 立即关闭执行服务
executorService.shutdownNow();
// 打印返回结果
Console.log(StrUtil.format("submit1:{},submit2:{}", submit1.get(), submit2.get()));
}
}
多线程状态
- 新建:New
- 就绪:Runnable
- 运行:Running
- 阻塞:Blocked
- 死亡:Dead
多线程同步
由于在同一个进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制,当一个线程获得对象的排它锁,独占资源,其他线程必须进行等待,使用后释放锁即可。
- Synchronized(隐式锁)
- ReentrantLock(可重入显式锁)
死锁
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待双方释放资源,都停止执行的情形,某一个同步块同时拥有两个以上对象的锁时,就可能会产生死锁的问题。
产生死锁的四个必要条件
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干个进程之间形成一种头尾相接的循环等待资源关系
多线程通信
基于 synchronized && Object
wait() 导致当前线程等待
notify() 唤醒正在等待对象监视器的单个线程
notifyAll() 唤醒正在等待对象监视器的所有线程
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
/**
* 学习多线程-Synchronized等待、唤醒
*
* @author _running
* @since 2022-05-10
*/
public class StudyWaitAndNotify {
public static void main(String[] args) {
Operate o = new Operate();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.increase();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.reduce();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.increase();
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.reduce();
}
}, "D").start();
}
}
class Operate {
int count = 0;
public synchronized void increase() {
while (count == 10){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Console.log(StrUtil.format("{}=>{}", Thread.currentThread().getName(), count++));
this.notify();
}
public synchronized void reduce() {
while (count == 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Console.log(StrUtil.format("{}=>{}", Thread.currentThread().getName(), count--));
this.notify();
}
}基于 Lock && Condition
await() 导致当前线程等到发信号或中断这个线程
signal() 唤醒一个等待线程
signalAll() 唤醒所有等待线程
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85package cn.running.multithreading.coding;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 学习多线程-Lock等待、唤醒
*
* @author _running
* @since 2022-05-10
*/
public class StudyAwaitAndSignal {
public static void main(String[] args) {
Operate2 o = new Operate2();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.increase();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.reduce();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.increase();
}
}, "C").start();
new Thread(() -> {
for (int i = 0; i < 24; i++) {
o.reduce();
}
}, "D").start();
}
}
class Operate2 {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
int count = 0;
public void increase() {
try {
lock.lock();
while (count == 10) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Console.log(StrUtil.format("{}=>{}", Thread.currentThread().getName(), count++));
condition.signalAll();
} finally {
lock.unlock();
}
}
public void reduce() {
try {
lock.lock();
while (count == 0) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Console.log(StrUtil.format("{}=>{}", Thread.currentThread().getName(), count--));
condition.signalAll();
} finally {
lock.unlock();
}
}
}