线程生命周期
1. 线程的生命周期
-
新建(NEW):新创建了一个线程对象。
-
可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
-
运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
-
阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
- 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
2. 线程的状态
New
Runnable
Blocked
Waiting
Timed Waiting
Terminated
/**
* 线程状态测试
**/
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 10; i++) {
if (i == 5) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread.State state = thread.getState();
System.out.println(state);
thread.start();
state = thread.getState();
System.out.println(state);
while(state != Thread.State.TERMINATED) {
state = thread.getState();
System.out.println(state);
Thread.sleep(100);
}
}
}
3. 创建线程(new)
(1)继承Thread类
- 继承Thread类,重写run方法
- 启动线程:子类对象.start()
- 不建议使用:避免OOP单继承局限性
public class TestThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("----------我在听歌");
}
}
public static void main(String[] args) {
TestThread t = new TestThread();
t.start();
for (int i = 0; i < 2000; i++) {
System.out.println("我在看电视");
}
}
}
(2) 实现Runnable接口
- 实现Runnable接口,重写run方法
- 启动线程:传入目标对象+Thread对象.start()(代理模式)
- 推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用。
public class TestRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("我在学习---------");
}
}
public static void main(String[] args) {
TestRunnable runnable = new TestRunnable();
new Thread(runnable).start();
for (int i = 0; i < 1000; i++) {
System.out.println("我在听歌");
}
}
}
/**
* 多线程测试: 同一个对象被多个线程使用,抢票问题
*/
public class TestRunnable3 implements Runnable {
private int ticket = 5;
public static void main(String[] args) {
TestRunnable3 runnable3 = new TestRunnable3();
new Thread(runnable3, "小红").start();
new Thread(runnable3, "老师").start();
new Thread(runnable3, "黄牛").start();
}
@Override
public void run() {
while (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "拿到了第" + ticket-- + "张票");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
练习:模拟多线程——龟兔赛跑
- 同一条赛道,兔子每隔一段时间休息一次。
public class Race implements Runnable {
/**
* 获胜者
*/
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
boolean flag = isOver(i);
if (flag) {
break;
}
//模糊兔子睡觉
if(Thread.currentThread().getName().equals("兔子") && i % 20 == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "跑了" + i + "步");
}
}
/**
* 判断游戏是否结束
* @return
*/
public boolean isOver(int steps) {
if (winner != null && winner != "") {
return true;
}
if (steps == 100) {
winner = Thread.currentThread().getName();
System.out.println("获胜者是" + winner);
return true;
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race, "乌龟").start();
new Thread(race, "兔子").start();
}
}
(3)实现callable接口
- Callable接口更像是Runnable接口的增强版,相比较Runable接口,Call()方法新增捕获和抛出异常的功能
- Call()方法可以返回值,调用FutureTask的get()方法来获取返回值
- Future接口提供了一个实现类FutureTask实现类,FutureTaks类用来保存Call()方法的返回值,并作为Thread类的target。
- 实现callable接口,重写call方法,需要返回值
/**
* 线程创建,实现callable接口
*/
public class TestCallable implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"在听歌");
}
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable callable = new TestCallable();
FutureTask<Boolean> futureTask = new FutureTask<Boolean>(callable);
new Thread(futureTask,"张三").start();
FutureTask<Boolean> futureTask2 = new FutureTask<Boolean>(callable);
new Thread(futureTask2,"李四").start();
boolean flag = futureTask.get();
System.out.println(flag);
}
}
4. 停止线程(Dead)
标志位——Running->Dead
public class TestStopThread implements Runnable {
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag) {
System.out.println(i++);
}
}
public synchronized void stop() {
flag = false;
}
public static void main(String[] args) {
TestStopThread stopThread = new TestStopThread();
new Thread(stopThread).start();
for (int i = 0; i < 100; i++) {
System.out.println("main"+i);
if(i == 90) {
stopThread.stop();
}
}
}
}
3. 阻塞线程(Block)
sleep——Running->Block
-
sleep 指定阻塞线程的毫秒数,时间到达后线程进入***就绪状态***
-
sleep存在异常InterruptedException
-
每一个对象都有一个锁,sleep不会释放锁
/**
* 模拟网络延时,放大线程不安全的问题
**/
public class TestSleep implements Runnable {
private int tickets = 10;
@Override
public void run() {
while (true) {
if (tickets >= 1) {
System.out.println(Thread.currentThread().getName() + "拿到了第" + tickets-- + "张票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
break;
}
}
}
public static void main(String[] args) {
TestSleep sleep1 = new TestSleep();
new Thread(sleep1, "小明").start();
new Thread(sleep1, "老师").start();
new Thread(sleep1, "黄牛").start();
}
}
/**
* 模拟倒计时
*/
public class TestSleep2{
private static int number = 10;
public static void run() {
while (true) {
if (number >= 1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(number--);
} else {
break;
}
}
}
public static void main(String[] args) {
run();
}
}
join——Running->Block
- join相当于插队,其他线程阻塞
package state.join;
/**
* join测试
*/
public class TestJoin implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("vip: " + i + "来了");
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new TestJoin());
thread.start();
for (int i = 0; i < 100; i++) {
if(i == 88) {
thread.join();
}
System.out.println("当前正在排队:"+i);
}
}
}
5. 线程就绪(Runnable)
yield(礼让)——Running->Runnable
- 让正在进行的线程暂停,但不阻塞
- 将线程从运行状态转为就绪状态
- 让CPU重新调度,礼让不一定成功,看CPU心情
6. 线程优先级 priority
- 优先级并不一定起作用,只是作为参考,实际调度取决于cpu
public class TestPriority implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "->" + Thread.currentThread().getPriority());
}
public static void main(String[] args) {
TestPriority t = new TestPriority();
Thread t1 = new Thread(t, "t1");
Thread t2 = new Thread(t, "t2");
Thread t3 = new Thread(t, "t3");
Thread t4 = new Thread(t, "t4");
t1.start();
t2.setPriority(3);
t2.start();
t3.setPriority(Thread.MAX_PRIORITY);
t3.start();
t4.setPriority(6);
t4.start();
}
}
7. 守护线程 daemon
-
线程分为守护线程和用户线程
-
虚拟机必须确保用户线程执行完毕
-
虚拟机不需要等待守护线程执行完毕
package daemon;
public class TestDaemon {
public static void main(String[] args) {
Thread thread = new Thread(new God());
thread.setDaemon(true);
thread.start();
new Thread(new People()).start();
}
}
class God implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("上帝守护着你");
}
}
}
class People implements Runnable {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
System.out.println("今年" + i + "岁");
if (i == 100) {
System.out.println("goodbye");
}
}
}
}
8. 同步方法和同步块 synchronized
- 同步块锁的对象是变化的对象,一般为增删改的对象
- 隐式锁,自动释放
- 有代码块锁和方法锁
package asyc;
import java.util.ArrayList;
import java.util.List;
public class TestList {
public static void main(String[] args) throws InterruptedException {
List list = new ArrayList<>();
synchronized (list) {
for (int i = 0; i < 1000; i++) {
Thread thread = new Thread(() -> {
list.add(Thread.currentThread().getName());
});
thread.start();
}
}
Thread.sleep(1000);
System.out.println(list.size());
}
}
9. 死锁
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之
一不满足,就不会发生死锁。
死锁的解除与预防:
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何不让这四个必要条件成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给予合理的规划。
package asyc;
public class DeadLock {
public static void main(String[] args) {
Makeup a = new Makeup("白雪公主",0);
Makeup b = new Makeup("灰姑娘",1);
new Thread(a).start();
new Thread(b).start();
}
}
class Tipstick {
}
class Mirror{
}
class Makeup implements Runnable{
static private Tipstick tipstick = new Tipstick();
static private Mirror mirror = new Mirror();
private int choice;
private String name;
Makeup(String name,int choice) {
this.name = name;
this.choice = choice;
}
public void makeup() throws InterruptedException {
if( choice == 0) {
synchronized (tipstick) {
System.out.println(this.name + "拿到口红");
Thread.sleep(1000);
// synchronized (mirror) { //循环等待,产生死锁
// System.out.println(this.name + "拿到镜子");
// }
}
synchronized (mirror) {
System.out.println(this.name + "拿到镜子");
}
} else {
synchronized (mirror) {
System.out.println(this.name + "拿到镜子");
Thread.sleep(3000);
// synchronized (tipstick) { // //循环等待,产生死锁
// System.out.println(this.name + "拿到口红");
// }
}
synchronized (tipstick) {
System.out.println(this.name + "拿到口红");
}
}
}
@Override
public void run() {
try {
this.makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
10. Lock锁
- 显式定义锁,需要手动关闭锁
- 代码块锁
- 性能:Lock锁 > 同步代码块(synchronized) > 同步方法(synchronized)
package asyc;
import java.util.concurrent.locks.ReentrantLock;
public class BuyTickets implements Runnable {
private int tickets = 1000;
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (tickets > 0) {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "购买了第" + tickets-- + "张票");
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
BuyTickets buyTickets = new BuyTickets();
new Thread(buyTickets, "小明").start();
new Thread(buyTickets, "张三").start();
}
}
生产者消费者问题
-
单一生产者和单一消费者
-
notifyALl:唤醒所有 wait 线程
-
notify:随机唤醒一个wait线程
管程法
package pc;
public class TestPC {
public static void main(String[] args) {
Container container = new Container();
Producer producer = new Producer(container);
Consumer consumer = new Consumer(container);
new Thread(producer).start();
new Thread(consumer).start();
}
}
/**
* 生产者
*/
class Producer implements Runnable {
private Container container;
Producer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
Chicken chicken = new Chicken(i);
System.out.println("生产者生产了第" + i + "只鸡");
container.push(chicken);
}
}
}
/**
* 消费者
*/
class Consumer implements Runnable {
private Container container;
Consumer(Container container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("消费了第" + container.pop().getId() + "只鸡");
}
}
}
/**
* 缓冲区
*/
class Container {
//初始化大小
Chicken[] chickens = new Chicken[10];
//计数器,当前存放个数
int count = 0;
public synchronized void push(Chicken chicken) {
if (count == 9) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
chickens[count] = chicken;
count++;
this.notifyAll();
}
public synchronized Chicken pop() {
if (count == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
Chicken product = chickens[count];
this.notifyAll();
return product;
}
}
/**
* 生产的物品
*/
class Chicken {
private int id;
Chicken(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
信号灯法
package pc;
public class TestPc2 {
public static void main(String[] args) {
Toy toy = new Toy();
I i = new I(toy);
You you = new You(toy);
new Thread(i).start();
new Thread(you).start();
}
}
/**
* 玩具
*/
class Toy {
boolean flag = true;
public synchronized void Iplaying() throws InterruptedException {
if(!flag) {
this.wait();
}
System.out.println("我在玩玩具");
this.notifyAll();
flag = !flag;
}
public synchronized void Youplaying() throws InterruptedException {
if(flag) {
this.wait();
}
System.out.println("你在玩玩具");
this.notifyAll();
flag = !flag;
}
}
class I implements Runnable {
private Toy toy;
I(Toy toy) {
this.toy = toy;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i % 2 == 0) {
try {
this.toy.Iplaying();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class You implements Runnable {
private Toy toy;
You(Toy toy) {
this.toy = toy;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i % 2 != 0) {
try {
this.toy.Youplaying();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
线程池
package pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestPool {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
TestThread testThread = new TestThread();
service.execute(testThread);
service.execute(testThread);
service.execute(testThread);
service.execute(testThread);
service.shutdown();
}
}
class TestThread implements Runnable {
@Override
public void run() {
System.out.println("Hello");
}
}
扩展
静态代理
-
类比多线程创建方式
new Thread(futureTask2,"李四").start();
new Thread 为代理对象,futureTask2为真实对象
-
下面以结婚为例,对象为真实角色,婚庆公司为真实角色
public class TestStaticProxy {
public static void main(String[] args) {
new WeddingCompany(new Person()).marry();
}
}
/**
* 结婚
*/
interface Marry {
void marry();
}
/**
* 真实角色
*/
class Person implements Marry {
@Override
public void marry() {
System.out.println("小明要结婚了");
}
}
/**
* 婚庆公司,代理角色
*/
class WeddingCompany implements Marry {
private Marry target;
public WeddingCompany(Marry target) {
this.target = target;
}
public void before() {
System.out.println("婚前布置现场");
}
public void marry() {
before();
target.marry();
after();
}
public void after() {
System.out.println("婚后收尾款");
}
}
lambda表达式(函数式接口)
- 函数式接口:只有一个方法的接口
- lambda表达式演化过程:外部类->静态内部类->局部内部类->匿名内部类->lambda表达式
- 类比多线程创建方式
new Thread(futureTask2,"李四").start();
Thread类也继承了Runnable接口
/**
* 推导lambda表达式
*/
public class TestLambda {
/**
* 3. 静态内部类
*/
static class Like implements ILike {
@Override
public void like() {
System.out.println("I like Lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.like();
/**
* 4. 局部内部类
*/
class Like implements ILike {
@Override
public void like() {
System.out.println("I like Lambda3");
}
}
like = new Like();
like.like();
/**
* 4. 匿名内部类,没有类名称
*/
ILike like2 = new ILike() {
@Override
public void like() {
System.out.println("I like Lambda4");
}
};
like2.like();
/**
* 5. lambda表达式
*/
ILike like3 = () -> System.out.println("I like lambda5");
like3.like();
}
}
/**
* 2. 实现类
*/
class Like implements ILike {
@Override
public void like() {
System.out.println("I like Lambda");
}
}
/**
* 1. 函数式接口
*/
interface ILike {
void like();
}