线程
1、概念![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/eaa201a82ceda2eadf7b66171eeeb1d1.png#pic_center)
2、调度
3.1、Java中线程的创建方式一----继承Thread类
3.2、Java中线程的创建方式一----实现Runnable接口
3.3Thread和Runnable创建多线程的区别
3.4匿名内部类方式实现线程的创建
4.1、多线程原理----随机打印结果
4.2、多线程原理----多线程内存图解
5.1Thread类的常用方法----获取线程名
5.2Thread类的常用方法----设置线程名
5.3Thread类的常用方法----sleep
6.1线程安全问题
6.2线程安全问题原理
6.3.1线程安全问题解决办法----同步代码块
6.3.2同步技术原理
6.4.1线程安全问题解决办法----同步方法
6.4.2线程安全问题解决办法----静态同步方法
6.5线程安全问题解决办法----lock锁机制
7.1线程状态概述
ps(阻塞状态是具有cpu的执行资格的,只不过需要和其他线程进行争夺,没争夺到cpu执行资格就会进入阻塞状态。计时等待状态和无限等待状态不是没有cpu执行资格的,它们都主动放弃了cpu的执行资格)
7.2无限等待唤醒案例分析(线程之间的通信)
7.3无限等待唤醒案例分析以及代码实现
package com.thread.waitAndNotify;
/**
* @ClassName waitAndNotifyDemo
* @Description TODO
* @Author Administrator
* @Date 2020/11/7 17:12
* @Version 1.0
**/
public class waitAndNotifyDemo {
public static void main(String[] args) {
//创建对象锁,保证唯一
Object obj = new Object();
//创建顾客匿名内部类(消费者)
new Thread() {
@Override
public void run() {
//一直有顾客买包子
while (true){
//保证等待和唤醒线程只能有一个同一时间执行,需要使用到同步代码块
synchronized (obj) {
System.out.println("告知老板所要包子种类和数量");
//调用wait()方法放弃cpu的执行资格,进入WAITING状态(无限等待)
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("包子已经做好了,开吃!");
System.out.println("-----------------------------");
}
}
}
}.start();
//创建老板匿名内部类(生产者)
new Thread() {
@Override
public void run() {
//老板一直在做包子
while (true){
//老板花5秒做包子
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//保证等待和唤醒线程只能有一个同一时间执行,需要使用到同步代码块
synchronized (obj) {
System.out.println("5秒后,老板把包子做好了,告知顾客可以吃包子了");
obj.notify();
}
}
}
}.start();
}
}
打印截图
7.4 Object类中wait带参方法和notifyAll方法
8.1等待唤醒机制(案例)
8.2包子铺类(生产者)和吃包子类(消费者)编写步骤分析
8.3等待唤醒机制代码实现
包子类
package com.thread.day07;
/**
* @ClassName BaoZi
* @Description TODO
* @Author Administrator
* @Date 2020/11/8 8:29
* @Version 1.0
**/
//包子实体类
public class BaoZi {
private String pi;//皮
private String xian;//馅
private boolean flag;//true:有包子,flase:无包子
public String getPi() {
return pi;
}
public void setPi(String pi) {
this.pi = pi;
}
public String getXian() {
return xian;
}
public void setXian(String xian) {
this.xian = xian;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
包子铺类(生产者)
package com.thread.day07;
/**
* @ClassName BaoZiPu
* @Description TODO
* @Author Administrator
* @Date 2020/11/8 8:31
* @Version 1.0
**/
//包子铺
public class BaoZiPu extends Thread {
private BaoZi baoZi;
public BaoZiPu(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
int count = 0;//定义一个计数变量,根据count取模值不同来生产不同的包子
//循环一直生产包子
while (true) {
synchronized (baoZi) {
//flag为true表示有包子,进入等待状态
if (baoZi.isFlag() == true) {
try {
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
//根据count取模值不同来生产不同的包子
if (count % 2 == 0) {
baoZi.setPi("薄皮");
baoZi.setXian("三鲜馅");
} else {
baoZi.setPi("冰皮");
baoZi.setXian("牛肉馅");
}
count++;
//flag为flase表示没有包子,要生产包子
System.out.println("包子铺开始生产包子");
//花费三秒生产包子
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//包子生产好了
System.out.println(baoZi.getPi() + baoZi.getXian() + "包子做好了");
//将包子状态改为true
baoZi.setFlag(true);
//唤醒包子线程吃包子
baoZi.notify();
}
}
}
}
}
//吃包子类(消费者)
package com.thread.day07;
/**
* @ClassName EatBaoZi
* @Description TODO
* @Author Administrator
* @Date 2020/11/8 9:05
* @Version 1.0
**/
//吃包子类
public class EatBaoZi extends Thread {
private BaoZi baoZi;
public EatBaoZi(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
//循环一直吃包子
while (true) {
synchronized (baoZi) {
//flag为false表示此时没有包子可以吃,进入等待状态
if (baoZi.isFlag() == false) {
try {
baoZi.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//否则表示有包子,则开始吃包子
System.out.println("吃货开始吃"+baoZi.getPi() + baoZi.getXian()+"包子");
baoZi.setFlag(false);
System.out.println("吃货已经吃完" + baoZi.getPi() + baoZi.getXian() + "包子");
//唤醒包子铺线程,生产包子
baoZi.notify();
System.out.println("------------------------------------------------");
}
}
}
}
测试类
package com.thread.day07;
/**
* @ClassName Test
* @Description TODO
* @Author Administrator
* @Date 2020/11/8 9:11
* @Version 1.0
**/
public class Test {
public static void main(String[] args) {
//创建包子对象
BaoZi baoZi= new BaoZi();
//创建包子铺线程,开启线程,生产包子
new BaoZiPu(baoZi).start();
//创建包子线程,开启线程,吃包子
new EatBaoZi(baoZi).start();
}
}
打印效果截图
9.1线程池概念和原理
9.2线程池分析及代码实现
Runnable实现类
package com.thread.day07.threadPool;
/**
* @ClassName RunnableImpl
* @Description TODO
* @Author Administrator
* @Date 2020/11/8 9:59
* @Version 1.0
**/
public class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了一个线程任务");
}
}
创建线程池类
package com.thread.day07.threadPool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @ClassName TheadPoolDemo
* @Description TODO
* @Author Administrator
* @Date 2020/11/8 9:57
* @Version 1.0
**/
public class TheadPoolDemo {
public static void main(String[] args) {
//通过Executors工厂生产线程池,假设为池子创建两个线程
ExecutorService executorService = Executors.newFixedThreadPool(2);
//executorService接口中有一个submit方法,用来开启线程,并执行传入runnable实现类的中的线程任务
executorService.submit(new RunnableImpl());
executorService.submit(new RunnableImpl());
executorService.submit(new RunnableImpl());
//executorService接口中有一个shutdown方法用来销毁线程池,不推荐使用
executorService.shutdown();
}
}
打印效果截图
ps(当线程执行完任务时会自动归还到线程池中,供其他方法使用)