本帖最后由 小石姐姐 于 2018-4-26 10:47 编辑
多线程课程笔记
+---------------------------+
| 阻塞 |
+--v----------------------^-+
| |
|解除阻塞 被阻塞|
new | |
+------+ +--v---+ +--^---+ +------+
| | start() | >--------------> | 线程执行结束 | |
| 创建 >------------> 就绪 | CPU调度 | 运行 >---------------> 销毁 |
| | | <--------------< | | |
+------+ +------+ +------+ +------+
```
**线程之间的通信**
- 使用`Object`类的成员方法
- `void wait()`: 使当前线程处于等待状态, 并且会立刻释放锁
- `void notify()`: 随机唤醒一个处于等待状态的线程
- `void notifyAll()`: 唤醒所有处于等待状态的线程
- 注意: **这三个方法必须在同步代码块中, 且只能用锁对象来调用, 否则会抛异常**
- `sleep()`和`wait()`的区别
- sleep
- 让当前线程在指定时间内睡眠, 时间结束后继续执行
- 是Thread类的静态方法
- 不会释放锁
- wait
- 让当前线程等待, 直到有人唤醒
- 是Object类的非静态方法
- 等待会立刻释放锁死锁: dead lock
发生死锁的原因:
同步代码块内的线程, 可能处在死循环, IO阻塞, sleep()状态, 导致内部持有锁的线程无法出同步代码块 多个线程互相持有锁又不释放锁: 两个线程执行的任务都是双层同步代码块, 每层同步都需要一个锁, 两个线程中同步代码块的锁是相反的
死锁的结果: 程序卡死, 无法继续执行 如何避免死锁:
// 嵌套同步代码块演示死锁
public class Test {
// 定义2个锁对象
public static String lock1 = "{锁1}";
public static String lock2 = "{锁2}";
public static void main(String[] args) {
// 创建2个线程对象
MyThread1 thread1 = new MyThread1();
MyThread2 thread2 = new MyThread2();
thread1.setName("MyThread1");
thread2.setName("MyThread2");
// 开始执行
thread1.start();
thread2.start();
// 注意观察控制台的小红点
}
}
class MyThread1 extends Thread {
@Override
public void run() {
System.out.println(getName() + "线程开始执行run()");
// 外层同步代码块, 使用锁1
synchronized (Test.lock1) {
System.out.println(getName() + "线程拿到了" + Test.lock1);
// 睡一下
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 内层同步代码块, 使用锁2
synchronized (Test.lock2) {
System.out.println(getName() + "持有2把锁");
}
}
}
}
class MyThread2 extends Thread {
@Override
public void run() {
System.out.println(getName() + "线程开始执行run()");
// 外层同步代码块, 使用锁2
synchronized (Test.lock2) {
System.out.println(getName() + "线程拿到了" + Test.lock2);
// 睡一下
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 内层同步代码块, 使用锁1
synchronized (Test.lock1) {
System.out.println(getName() + "持有2把锁");
}
}
}
}另一种加锁方式: Lock类
// 创建锁对象, 该锁对象也要所有线程共享唯一一个
private Lock lock = new ReentrantLock();
lock.lock(); // 加锁, 相当于执行到synchronized
// 同步的代码
lock.unlock(); // 释放锁, 相当于同步代码块执行完毕
|
|