### 状态代码演示
#### 展示线程的 NEW RUNNABLE TERMINATED 状态
```java
package threadcoreknowledge.sixstates;
/**
* 展示线程的 NEW RUNNABLE TERMINATED 状态
* 即使是正在运行,也是Runnable状态,而不是Running.
*/
public class NewRunableTerminated implements Runnable {
public static void main(String[] args) {
Thread thread = new Thread(new NewRunableTerminated());
// 打印出NEW的状态
System.out.println(thread.getState());
thread.start();
System.out.println(thread.getState());
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 打印出Runnable的状态,即使是正在运行的线程,也是Runnable, 而不是Running
System.out.println(thread.getState());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 将会打印出TERMINATED状态
System.out.println(thread.getState());
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
}
```
#### 展示 Blocked, Waiting, Timed Waiting 状态
```java
package threadcoreknowledge.sixstates;
/**
* 展示 Blocked, Waiting, Timed Waiting
*/
public class BlockedWaitingTimedWaiting implements Runnable {
public static void main(String[] args) throws InterruptedException {
BlockedWaitingTimedWaiting runnable = new BlockedWaitingTimedWaiting();
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
Thread.sleep(10);
// 打印出Timed Waiting状态,因为正在执行Thread.sleep(1000);
System.out.println(thread1.getState());
// 打印出Blocked状态,因为thread2想拿到syn()的锁却拿不到
System.out.println(thread2.getState());
Thread.sleep(1300);
// 打印出Waiting状态,因为执行了wait()
System.out.println(thread1.getState());
}
@Override
public void run() {
syn();
}
public synchronized void syn() {
try {
Thread.sleep(1000);
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
```
### 阻塞状态是什么?

### 常见面试问题

回答状态转换图。
## 第7章 趣解Thread和Object类中线程相关方法
### 思考题

### 本小节概览


### 相关方法概览


### wait, notify, notifyall的作用
#### 阻塞阶段
调用wait()进入阻塞阶段
在`synchronized`里面使用`wait()`, 然后线程进入阻塞状态。
直到以下4种情况之一发生时,才会被唤醒。

#### 唤醒阶段
调用notify() 、notifyAll()
#### 遇到中断
#### 代码展示1:
```java
package threadcoreknowledge.threadobjectclasscommonmethods;
/**
* 展示 wait 和 notify 的基本用法
* 1. 研究代码执行顺序
* 2. 证明wait释放锁
*/
public class Wait {
public static Object object = new Object();
static class Thread1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(Thread.currentThread().getName() + "开始执行了");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "获取到了锁,继续执行");
}
}
}
static class Thread2 extends Thread {
@Override
public void run() {
synchronized (object) {
object.notify();
System.out.println(Thread.currentThread().getName() + "调用了notify()");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread1 thread1 = new Thread1();
Thread2 thread2 = new Thread2();
thread1.start();
Thread.sleep(200);
thread2.start();
}
}
```
可能的执行结果:
```
Thread-0开始执行了
Thread-1调用了notify()
Thread-0获取到了锁,继续执行
```
此段代码说明了两点:
1. 研究代码执行顺序
2. 证明wait释放锁
#### 代码展示2:
演示 notifyAll() 用法。
```java
package threadcoreknowledge.threadobjectclasscommonmethods;
/**
* 描述: 3个线程,线程1和线程2首先被阻塞,线程3唤醒它们。有两种选择,notify, notifyAll
*
* start先执行,不代表线程先启动
*/
public class WaitNotifyAll implements Runnable {
private static final Object resourceA = new Object();
public static void main(String[] args) throws InterruptedException {
WaitNotifyAll r = new WaitNotifyAll();
Thread thread1 = new Thread(r);
Thread thread2 = new Thread(r);
Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceA) {
resourceA.notifyAll();
System.out.println("Thread C notified.");
}
}
});
thread1.start();
thread2.start();
Thread.sleep(200);
thread3.start();
}
@Override
public void run() {
synchronized (resourceA) {
System.out.println(Thread.currentThread().getName() + " got resourceA lock.");
try {
System.out.println(Thread.currentThread().getName() + " waits to start.");
resourceA.wait();
System.out.println(Thread.currentThread().getName() + " is waiting to end.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
```
可能的执行结果:
```
Thread-0 got resourceA lock.
Thread-0 waits to start.
Thread-1 got resourceA lock.
Thread-1 waits to start.
Thread C notified.
Thread-1 is waiting to end.
Thread-0 is waiting to end.
```
#### 代码展示3:
证明`wait()`只释放**当前对象**的那把锁
```java
package threadcoreknowledge.threadobjectclasscommonmethods;
/**
* 证明wait()只释放当前的那把锁
*/
public class WaitNotifyReleaseOwnMonitor {
public static volatile Object resourceA = new Object();
public static volatile Object resourceB = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceA) {
System.out.println("ThreadA gets resourceA lock.");
synchronized (resourceB) {
System.out.println("ThreadA gets resourceB lock.");
try {
System.out.println("ThreadA releases resourceA lock.");
resourceA.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (resourceA) {
System.out.println("ThreadB gets resourceA lock.");
System.out.println("ThreadB tries to get resourceB lock.");
synchronized (resourceB) {
System.out.println("ThreadB gets resourceB lock.");
}
}
}
});
thread1.start();
thread2.start();
}
}
```
可能的执行结果:
```
ThreadA gets resourceA lock.
ThreadA gets resourceB lock.
ThreadA releases resourceA lock.
ThreadB gets resourceA lock.
ThreadB tries to get resourceB lock.
```
### wait, notify, notifyall的特点性质
- 使用的时候必须先拥有monitor
- notify只能唤醒其他线程的其中一个,不确定具体唤醒哪一个,这由`JVM`决定。
- 三个方法都属于Object类。都是用`final native`修饰的。
- 类似功能的Condition类。
- 同时持有**多个锁**的情况
### wait原理


### 状态转化的特殊情况

### wait/notify实现生产者/消费者模式
```java
package threadcoreknowledge.threadobjectclasscommonmethods;
import java.util.Date;
import java.util.LinkedList;
/**
* 用wait/notify实现生产者消费者模式
*/
public class ProducerConsumerModel {
public static void main(String[] args) {
EventStorage storage = new EventStorage();
Producer producer = new Producer(storage);
Consumer consumer = new Consumer(storage);
new Thread(producer).start();
new Thread(consumer).start();
}
}
class Producer implements Runnable {
private EventStorage storage;
public Producer(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.put();
}
}
}
class Consumer implements Runnable {
private EventStorage storage;
public Consumer(EventStorage storage) {
this.storage = storage;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
storage.take();
}
}
}
class EventStorage {
private int maxSize;
private LinkedList
* 通过debugger看线程join前后状态的对比
*/
public class JoinThreadState {
public static void main(String[] args) throws InterruptedException {
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println(mainThread.getState());
System.out.println("Thread-0 运行结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
System.out.println("等待子线程运行完毕");
thread.join();
System.out.println("子线程运行完毕");
}
}
```
join的源码
```java
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
```
join的源码中没有notify的操作,那么子线程结束之后,是怎么通知/唤醒主线程的呢?

线程执行完毕退出的时候,执行了notifyall操作。
等价的Java代码,实现join这个功能。
```java
package threadcoreknowledge.threadobjectclasscommonmethods;
/**
* 通过讲解join的原理,讲解join的代替写法
*/
public class JoinPrinciple {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "运行结束");
}
});
thread.start();
System.out.println("等待子线程运行完毕");
// thread.join();
synchronized (thread) {
thread.wait();
}
System.out.println("子线程运行完毕");
}
}
```
但是
```java
synchronized (thread) {
thread.wait();
}
```
换成
```java
Object lock = new Object();
synchronized (lock) {
lock.wait();
}
```
并不等价。不使用thread变量作为锁,会导致主线程一直等待。
join面试题:

WAITING状态。
### yield
作用:释放我的CPU时间片,释放了时间片,线程仍处于runnable状态。
定位:JVM不保证遵循。
yield和sleep的区别:是否随时可能再次被调度。yield是可以随时可能再次被调度的。
```java
package threadcoreknowledge.threadobjectclasscommonmethods;
/**
* 演示打印main, Thread-0, Thread-1
*/
public class CurrentThread implements Runnable {
public static void main(String[] args) {
new CurrentThread().run();
new Thread(new CurrentThread()).start();
new Thread(new CurrentThread()).start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
```
`Thread.currentThread()`获取当前执行线程的引用。
## 线程的各个属性
> 什么时候我们需要设置守护线程?
通常情况下不需要设置。JVM提供的守护线程足够我们使用。
> 我们应该如何应用线程优先级来帮助程序运行?有哪些禁忌?
因为不同操作系统对于优先级的映射和调度都不一样,所以不应该使用优先级来帮助程序运行。
> 不同操作系统如何处理优先级问题?
不同操作系统对于优先级的映射和调度都不一样
### 线程各属性

```java
package threadcoreknowledge.threadobjectclasscommonmethods;
/**
* ID是从1开始的,JVM运行起来后,我们自己创建的线程的ID早已不是2
*/
public class Id {
public static void main(String[] args) {
Thread thread = new Thread();
System.out.println("主线程的ID: " + Thread.currentThread().getId());
System.out.println("子线程的ID: " + thread.getId());
}
}
```
可能的执行结果:
```
主线程的ID: 1
子线程的ID: 11
```

`JVM`默认创建、启动了一些守护线程,完成特定的功能。
### 守护线程
作用:给用户线程提供服务。
3个特性:
1. 线程类型默认**继承**自父线程。用户线程创建出来的线程默认是用户线程,守护线程创建出来的线程默认是守护线程。
2. 被谁启动。通常守护线程由JVM启动。main线程除外,main线程是非守护线程。
3. 守护线程不影响JVM退出。
守护线程和普通线程的区别:
整体上无太大差别,都是执行代码的。用户线程执行我们的业务逻辑,守护线程服务于用户线程。
唯一区别在于JVM的离开。如果线程是一个用户线程,那么它会影响到JVM的退出,而守护线程并不会影响。
线程优先级:
10个级别,默认为5.
程序设计不应该依赖于优先级
- 不同操作系统不一样。在windows系统中只有7个优先级。
- 优先级会被操作系统改变。

## 多线程异常处理
自定义`UncaughtExceptionHandler`
```java
package threadcoreknowledge.uncaughtexception;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 自己编写的 UncaughtExceptionHandler
*/
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private String name;
public MyUncaughtExceptionHandler(String name) {
this.name = name;
}
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger logger = Logger.getAnonymousLogger();
logger.log(Level.WARNING, "线程异常,终止啦" + t.getName(), e);
System.out.println(name + "捕获了异常" + t.getName() + "异常" + e);
}
}
```
使用`UncaughtExceptionHandler`
```java
package threadcoreknowledge.uncaughtexception;
/**
* 使用自己定义的 UncaughtExceptionHandler
*/
public class UseOwnUncaughtExceptionHandler implements Runnable {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("自定义捕获器"));
new Thread(new UseOwnUncaughtExceptionHandler(), "Thread-1").start();
new Thread(new UseOwnUncaughtExceptionHandler(), "Thread-2").start();
new Thread(new UseOwnUncaughtExceptionHandler(), "Thread-3").start();
new Thread(new UseOwnUncaughtExceptionHandler(), "Thread-4").start();
}
@Override
public void run() {
throw new RuntimeException();
}
}
```
## 双刃剑:多线程会导致的问题
考考你:
> 一共有哪几类线程安全问题?3种。
a++
> 哪些场景需要额外注意线程安全问题?
> 什么是多线程带来的上下文切换?
### 线程安全
什么是线程安全?
> 《Java Concurrency In Practice》的作者Brian Goetz对“线程安全”有一个比较恰当的定义:“当多个线程访问同一个对象时,如果不需要考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么这个对象是线程安全的。”
白话翻译:
不管业务中遇到怎样多个线程访问某对象或者某方法的情况,而在编写这个业务逻辑的时候,都不需要做任何额外的处理(也就是可以像单线程编程一样),程序也可以正常运行(不会因为多线程而出错),就可以称为线程安全。
什么情况下会出现线程安全问题?
- 运行**结果错误**:a++多线程下出现消失的请求现象
- **活跃性问题**:死锁、活锁、饥饿
- 对象**发布**和**初始化**的时候的安全问题。
#### 运行结果错误演示示例:
```java
package background;
/**
* 第一种:运行结果出错
* 演示计数不准确(减少),找出具体出错的位置
*/
public class MultiThreadsError implements Runnable {
int index = 0;
static MultiThreadsError instance = new MultiThreadsError();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(instance.index);
}
@Override
public void run() {
// while (index < 10000) {
// index++;
// }
for (int i = 0; i < 10000; i++) {
index++;
}
}
}
```
原因是`index++`不是原子操作。

`a++`具体消失在哪里?请看代码。来自悟空老师。我目前还看不懂。
```java
package background;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 第一种:运行结果出错
* 演示计数不准确(减少),找出具体出错的位置
*/
public class MultiThreadsError implements Runnable {
int index = 0;
static MultiThreadsError instance = new MultiThreadsError();
final boolean[] marked = new boolean[1000000];
static AtomicInteger realIndex = new AtomicInteger();
static AtomicInteger wrongIndex = new AtomicInteger();
static volatile CyclicBarrier cyclicBarrier1 = new CyclicBarrier(2);
static volatile CyclicBarrier cyclicBarrier2 = new CyclicBarrier(2);
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("表面上结果是:" + instance.index);
System.out.println("真正运行的次数:" + realIndex.get());
System.out.println("错误次数:" + wrongIndex.get());
}
@Override
public void run() {
// while (index < 10000) {
// index++;
// }
marked[0] = true;
for (int i = 0; i < 10000; i++) {
try {
cyclicBarrier2.reset();
cyclicBarrier1.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
index++;
try {
cyclicBarrier1.reset();
cyclicBarrier2.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
realIndex.incrementAndGet();
synchronized (instance) {
if (marked[index] && marked[index - 1]) {
System.out.println("发生错误" + index);
wrongIndex.incrementAndGet();
}
marked[index] = true;
}
}
}
}
```
#### 必然出现死锁的例子
```java
package background;
/**
* 第二种线程安全问题,演示死锁
*/
public class MultiThreadError2 implements Runnable {
int flag = 1;
// 锁对象 o1 o2 是两个线程共享的
static Object o1 = new Object();
static Object o2 = new Object();
public static void main(String[] args) {
MultiThreadError2 r1 = new MultiThreadError2();
MultiThreadError2 r2 = new MultiThreadError2();
r1.flag = 1;
r2.flag = 0;
new Thread(r1).start();
new Thread(r2).start();
}
@Override
public void run() {
System.out.println("flag = " + flag);
if (flag == 1) {
synchronized (o1) {
try {
Thread.sleep(500);
} catch(InterruptedException e) {
e.printStackTrace();
}
synchronized (o2) {
System.out.println("1");
}
}
}
if (flag == 0) {
synchronized (o2) {
try {
Thread.sleep(500);
} catch(InterruptedException e) {
e.printStackTrace();
}
synchronized (o1) {
System.out.println("0");
}
}
}
}
}
```
#### 对象发布和初始化


对象逸出情况1:方法返回一个private对象
```java
package background;
import java.util.HashMap;
import java.util.Map;
public class MultiThreadsError3 {
private Map