线程

基本概念

操作系统同时执行的多个任务,是进程。
进程同时执行的多个任务,是线程。

线程的生命周期:

新建 就绪 运行 阻塞 死亡
  1. 新建态 创建线程后,jvm分配内存
  2. 就绪态 start() 方法调用后
  3. 运行态 执行run()方法代码逻辑
  4. 阻塞态 失去当前资源后
  5. 死亡态

线程阻塞的情形:

  1. sleep()方法,会放弃占用资源
  2. wait()等待方法,会释放当前占用的锁
  3. suspend()挂起方法,容易产生死锁
  4. 当线程响要获得一个同步锁,但锁正在被其他线程使用
    当使用阻塞式IO时,同上

线程从阻塞恢复成就绪态的情形:

  1. 当经过sleep指定的时间,重新转为就绪
  2. notify notifyAll的方法时,重新转为就绪
  3. resume()方法可以恢复被挂起的线程
  4. 当成功拿到同步锁,转为就绪态,阻塞式IO同上

线程状态查看

Thread 内的 isAlive() true代表就绪,运行或阻塞状态
false 代表新建或死亡

控制线程

join 后台线程 yield(让步) 改变线程的优先级

线程概述

1.线程的创建方式

1.1 继承Thread类
1
2
3
public class MyThread extends Thread {

}
1.2 实现Runable接口来创建线程
1
2
3
public class RunableThread implements Runnable{

}

2.线程的执行原理

线程的并发执行是通过多个线程步断切换CPU的资源,这个速度非常快。

3.线程的生命周期

线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。

新建:就是刚使用new方法,new出来的线程;

就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;

运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;

阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;

销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;

完整的生命周期图如下:

image

并发

语法:synchronized

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
* @Description: 如果一个对象方法上有 synchronized 锁的对象就是this
* @Author: brew
* @Date: 2020-02-21 15:34
*/
public synchronized boolean saleTickets() {
boolean isFinish = false;
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "卖出座位是" + (ticket--) + "号");
} else {
isFinish = true;
}
return isFinish;
}

休眠

服务器端的程序,都需要给一个休眠的时间,在没有synchronized的代码块内,会让出cpu资源
1
2
3
4
5
6
7
8
while (true){
System.out.println(new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
static class MyThread implements Runnable{

static Object ojb= new Object();

@Override
public void run() {
while(true){
synchronized (ojb){
try {
//休眠如果在synchronized内就不会让出cpu资源
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

线程间的通信

1
2
3
4
5
graph LR
生产者-->水果篮子
消费者-->水果篮子
生产者-->消费者
消费者-->生产者
消费者等待水果篮子的水果,生产者生产水果,生产者通知消费者有水果了,消费者消费完了没水果在通知生产者生产水果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Basket篮子
package com.brew.demo5;

/**
* @Author brew
* @Date 2020-02-21 15:54
*/
public class Basket {

private boolean isEmpty;

public boolean isEmpty() {
return isEmpty;
}

public void setEmpty(boolean empty) {
isEmpty = empty;
}
}

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
//生产者
package com.brew.demo5;

/**
* @Author brew
* @Date 2020-02-21 15:54
*/
public class Producer implements Runnable {

private Basket basket;

public Producer(Basket basket) {
super();
this.basket = basket;
}

@Override
public void run() {
while (true) {
//basket为同一个共享对象
synchronized (basket) {
try {
if (!basket.isEmpty()) {
//线程等待状态
basket.wait();
}
System.out.println("生产水果");
basket.setEmpty(false);
//通知在这个共享对象上等待的线程
basket.notify();

} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

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
//消费者
package com.brew.demo5;

/**
* @Author brew
* @Date 2020-02-21 16:03
*/
public class Consumer implements Runnable {
private Basket basket;

public Consumer(Basket basket) {
super();
this.basket = basket;
}

@Override
public void run() {
while (true) {
//basket为同一个共享对象
synchronized (basket) {
try {
if (basket.isEmpty()) {
//线程等待状态
basket.wait();
}
System.out.println("消费水果");
basket.setEmpty(true);
//通知在这个共享对象上等待的线程
basket.notify();

} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

线程的优先级

setPriority