线程基础内容
程序、进程、线程
- 程序:Program,是一个指令的集合
- 进程:Process,(正在执行中的程序)是一个静态的概念
- 进程是程序的一次静态态执行过程, 占用特定的地址空间
- 每个进程都是独立的,由3部分组成cpu,data,code
- 缺点:内存的浪费,cpu的负担
- 线程:是进程中一个“单一的连续控制流程” (a single sThread,equential flow of control)/执行路径
- 线程又被称为轻量级进程(lightweight process)。
- Threads run at the same time, independently of one another
- 一个进程可拥有多个并行的(concurrent)线程
- 一个进程中的线程共享相同的内存单元/内存地址空间->可以访问相同的变量和对象,而且它们从同一堆中分配对象->通信、数据交换、同步操作
- 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快。
- 进程与线程
• 一个进程中至少有一个线程
• 一个进程中的线程共享代码和数据空间
• 线程结束,进程未毕结束,但进程结束,线程一定结束 。
• 进程中包含线程,线程是进程的一部分- Javac与Java
Java虚拟机启动的时候会有一个进程java.exe,该进程中至少有一个线程,在负责java程序的执行。而且这个线程运行的代码存在于main方法中,该线程称之为主线程。
- Javac与Java
- 线程与进程的区别
线程的创建和启动
- 在Java中负责线程的这个功能的是Java.lang.Thread 这个类
可以通过创建 Thread 的实例来创建新的线程。 - 每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。
- 通过调用Thead类的start()方法来启动一个线程。
- 创建线程的方式一->继承Thread类
操作步骤:
【1】继承Thread类
【2】重写run方法
【3】创建对象,调用start()方法启动线程 - 创建线程的方式二->实现Runnable接口
操作步骤:
【1】实现Runnable接口
【2】重写run方法
【3】创建对象,调用start()方法启动线程 - 继承Thread类与实现Runnable接口
- 继承Thread类方式的缺点:如果类已经从一个类继承(如小程序必须继承自 Applet 类),则无法再继承Thread 类
- 通过Runnable接口实现多线程
优点:可以同时实现继承。实现Runnable接口方式要通用一些。
1)避免单继承
2)方便共享资源 同一份资源 多个代理访问
线程的生命周期
线程状态
-
新生状态
– 用new关键字建立一个线程后,该线程对象就处亍新生状态。
– 处于新生状态的线程有自己的内存空间,通过调用start()方法迚入就绪状态。 就绪状态
– 处于就绪状态线程具备了运行条件,但还没分配到CPU,处亍线程就绪队列,等待系统为其分 配CPU。
– 当系统选定一个等待执行的线程后,它就会从就绪状态迚入执行状态,该动作称为“CPU调度”。 -
运行状态
– 在运行状态的线程执行自己的run方法中代码,直到等待某资源而阻塞戒完成任何而死亡。
– 如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态。 -
阻塞状态
– 处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己运行,进入阻塞状态。
– 在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续执行。- sleep/yield/join方法可以暂停Thread执行
- sleep:不会释放锁,Sleep时别的线程也不可以访问锁定对象。
- yield:让出CPU的使用权,从运行态直接迚入就绪态。让CPU 重新挑选哪一个线程迚入运行状态。
- join:当某个线程等待另一个线程执行结束后,才继续执行时,使调用该方法的线程在此之前执行完毕,也就是等待调用该方法的线程执行完毕后再往下继续执行
-
死亡状态
– 死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有三个,一个是正常运行的线程完成了它的全部工作;另一个是线程被强制性地终止,如通过stop方法来终止一个线程【不推荐使用】;三是线程抛出未捕获的异常。
- 线程操作的相关方法
线程同步
线程同步的必要性
- 使用同步解决线程的安全性问题
同步的前提:
(1)必须有两个或两个以上的线程
(2)必须是多个线程使用同一资源
(3)必须保证同步中只能有一个线程在运行
线程同步的实现
-
同步代码块
-
将需要同步的代码放到方法中
-
同步监视器
– synchronized(obj){}中的obj称为同步监视器
– 同步代码块中同步监视器可以是任何对象,但是推荐使用共享资源作为同步监视器
– 同步方法中无需指定同步监视器,因为同步方法的监视器是this,也就是该对象本身 -
同步监视器的执行过程
– 第一个线程访问,锁定同步监视器,执行其中代码
– 第二个线程访问,发现同步监视器被锁定,无法访问
– 第一个线程访问完毕,解锁同步监视器
– 第二个线程访问,发现同步监视器未锁,锁定并访问
死锁
死锁一般情况下表示互相等待,是程序运行时出现的一种问题
线程间通信
线程间通信的必要性
线程间通信的实现
注意事项:以上方法都只能在同步方法或者同步代码块中使用,否则会抛出异常
本章总结
Thread
package com.petrel.demo;
/**
* @author Petrel
* @data 2020/6/28 11:42
*/
/**
* 实现多线程的时候:
* 1、需要继承Thread类
* 2、必须要重写run方法,指的是核心执行的逻辑
* 3、线程在启动的时候,不要直接调用run方法,而是要通过start()来进行调用
* 4、每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源无法进行人为控制
* 第二种实现方式:使用了代理设计模式
* 1、实现Runnable接口
* 2、重写run方法
* 3、创建Thread对象,将刚刚创建好的runnable的子类实现作为thread的构造参数
* 4、通过thread.start()进行启动
* 两种实现方式哪种用的比较多?
* 推荐使用第二种方式:
* 1、java是单继承,将继承关系留给最需要的类
* 2、使用runnable接口之后不需要给共享变量添加static关键字,每次创建一个对象,作为共享对象即可
* 线程的生命周期:
* 1、新生状态:
* 当创建好当前线程对象之后,没有启动之前(调用start方法之前)
* ThreadDemo thread = new ThreadDemo()
* RunnableDemo run = new RunnableDemo()
* 2、就绪状态:准备开始执行,并没有执行,表示调用start方法之后
* 当对应的线程创建完成,且调用start方法之后,所有的线程会添加到一个就绪队列中,所有的线程同时去抢占cpu的资源
* 3、运行状态:当当前进程获取到cpu资源之后,就绪队列中的所有线程会去抢占cpu的资源,谁先抢占到谁先执行,在执行的过程中就叫做运行状态
* 抢占到cpu资源,执行代码逻辑开始
* 4、死亡状态:当运行中的线程正常执行完所有的代码逻辑或者因为异常情况导致程序结束叫做死亡状态
* 进入的方式:
* 1、正常运行完成且结束
* 2、人为中断执行,比如使用stop方法
* 3、程序抛出未捕获的异常
* 5、阻塞状态:在程序运行过程中,发生某些异常情况,导致当前线程无法再顺利执行下去,此时会进入阻塞状态,进入阻塞状态的原因消除之后,
* 所有的阻塞队列会再次进入到就绪状态中,随机抢占cpu的资源,等待执行
* 进入的方式:
* sleep方法
* 等待io资源
* join方法(代码中执行的逻辑)
*
* 注意:
* 在多线程的时候,可以实现唤醒和等待的过程,但是唤醒和等待操作的对应不是thread类
* 而是我们设置的共享对象或者共享变量
* 多线程并发访问的时候会出现数据安全问题:
* 解决方式:
* 1、同步代码块
* synchronized(共享资源、共享对象,需要是object的子类){具体执行的代码块}
* 2、同步方法
* 将核心的代码逻辑定义成一个方法,使用synchronized关键字进行修饰,此时不需要指定共享对象
*
*/
/**
* 实现多线程的时候:
* 1、需要继承Thread类
* 2、必须要重写run方法,指的是核心执行的逻辑
* 3、线程在启动的时候,不要直接调用run方法,而是要通过start()来进行调用
* 4、每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源无法进行人为控制
*/
public class ThreadDemo extends Thread{
//run
@Override
public void run() {
//super.run();
for (int i = 0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"- - -"+i);
}
}
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
//threadDemo.run(); 错误示范 这样只是调用了run方法
threadDemo.start();//线程在启动的时候通过start(来进行调用
for (int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"------"+i);
}
}
}
Runnable接口
package com.petrel.demo;
/**
* @author Petrel
* @data 2020/6/28 12:19
*/
/**
* 第二种实现方式:使用了代理设计模式
* 1、实现Runnable接口
* 2、重写run方法
* 3、创建Thread对象,将刚刚创建好的runnable的子类实现作为thread的构造参数
* 4、通过thread.start()进行启动
*/
public class RunnableDemo implements Runnable {
@Override
public void run() {
for (int i = 0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"- - -"+i);
}
}
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo();
Thread thread = new Thread(runnableDemo);
thread.start();
for (int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"------"+i);
}
}
}
卖票
package com.petrel.ticket;
/**
* @author Petrel
* @data 2020/6/28 13:17
*/
public class TicketThread extends Thread{
private static int ticket = 5;
@Override
public void run() {
for(int i = 0;i<100;i++){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
}
}
}
public static void main(String[] args) {
TicketThread t1 = new TicketThread();
TicketThread t2 = new TicketThread();
TicketThread t3 = new TicketThread();
TicketThread t4 = new TicketThread();
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
运行结果:
Thread-0正在出售第4张票
Thread-1正在出售第5张票
Thread-0正在出售第3张票
Thread-0正在出售第1张票
Thread-1正在出售第2张票
这样是不正确的
*/
package com.petrel.ticket;
/**
* @author Petrel
* @data 2020/6/28 13:25
*/
//使用runnable接口之后不需要给共享变量添加static关键字,每次创建一个对象,作为共享对象即可
public class TickerRunnable implements Runnable{
private int ticket = 5;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
}
}
}
public static void main(String[] args) {
TickerRunnable ticket = new TickerRunnable();
Thread t1 = new Thread(ticket);
Thread t2 = new Thread(ticket);
Thread t3 = new Thread(ticket);
Thread t4 = new Thread(ticket);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
运行结果:
Thread-0正在出售第5张票
Thread-0正在出售第4张票
Thread-1正在出售第3张票
Thread-1正在出售第1张票
Thread-0正在出售第2张票
*/
package com.petrel.ticket;
/**
* @author Petrel
* @data 2020/6/28 13:25
*/
//TickerRunnable的加强版
// 多线程并发访问的时候会出现数据安全问题:
// 1、同步代码块 synchronized(共享资源、共享对象,需要是object的子类){具体执行的代码块}
public class TickerRunnable2 implements Runnable{
private int ticket = 5;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(200); //睡眠的时候其他线程可以抢占资源
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
}
}
}
}
public static void main(String[] args) {
TickerRunnable2 ticket = new TickerRunnable2();
Thread t1 = new Thread(ticket,"A");
Thread t2 = new Thread(ticket,"B");
Thread t3 = new Thread(ticket,"C");
Thread t4 = new Thread(ticket,"D");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
运行结果:
D正在出售第5张票
B正在出售第4张票
C正在出售第3张票
A正在出售第2张票
B正在出售第1张票
*/
package com.petrel.ticket;
/**
* @author Petrel
* @data 2020/6/28 13:25
*/
//TickerRunnable的加强版
// 多线程并发访问的时候会出现数据安全问题:
//2.同步方法 将核心的代码逻辑定义成一个方法,使用synchronized关键字进行修饰,此时不需要指定共享对象
public class TickerRunnable3 implements Runnable{
private int ticket = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.sale();
}
}
public synchronized void sale(){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this){
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "正在出售第" + (ticket--) + "张票");
}
}
}
public static void main(String[] args) {
TickerRunnable3 ticket = new TickerRunnable3();
Thread t1 = new Thread(ticket,"A");
Thread t2 = new Thread(ticket,"B");
Thread t3 = new Thread(ticket,"C");
Thread t4 = new Thread(ticket,"D");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
运行结果:
A正在出售第5张票
D正在出售第4张票
C正在出售第3张票
B正在出售第2张票
C正在出售第1张票
*/
线程的代理设计模式
package com.petrel.proxy;
public interface KindWomen {
public void makeEyesWithFriend();
public void playGamesWithFriend();
}
------------
package com.petrel.proxy;
/**
* @author Petrel
* @data 2020/6/28 15:10
*/
/**
* 代理人
* */
public class WangPo implements KindWomen{
private KindWomen kindWomen;
public WangPo(){
this.kindWomen = new PanJinLian();
}
public WangPo(KindWomen kindWomen){
this.kindWomen = kindWomen;
}
@Override
public void makeEyesWithFriend() {
this.kindWomen.makeEyesWithFriend();
}
@Override
public void playGamesWithFriend() {
this.kindWomen.playGamesWithFriend();
}
}
------------
package com.petrel.proxy;
/**
* @author Petrel
* @data 2020/6/28 15:13
*/
public class PanJinLian implements KindWomen {
@Override
public void makeEyesWithFriend() {
System.out.println("潘金莲在和朋友对视");
}
@Override
public void playGamesWithFriend() {
System.out.println("潘金莲在和朋友打游戏");
}
}
------------
package com.petrel.proxy;
/**
* @author Petrel
* @data 2020/6/28 15:15
*/
public class XiMenQing {
public static void main(String[] args) {
WangPo wangPo = new WangPo();
wangPo.makeEyesWithFriend();
wangPo.playGamesWithFriend();
}
}
线程类api方法
package com.petrel;
/**
* @author Petrel
* @data 2020/6/28 16:28
*/
//介绍线程类api方法
public class ThreadApiDemo implements Runnable{
public static void main(String[] args) {
//获取当前线程对象
Thread thread = Thread.currentThread();
//获取当前线程的名称
System.out.println(thread.getName()); //运行结果:main
//获取线程的id
System.out.println(thread.getId()); //运行结果:1
//获取线程的优先级,在一般系统中范围是0-10的值,如果没有经过设置的话,就是默认值5,有些系统是0-100
System.out.println(thread.getPriority()); //运行结果:5
//设置线程池的优先级 优先级越高不一定先执行,只是优先执行的概率比较大而已
thread.setPriority(10);
System.out.println(thread.getPriority()); //运行结果:10
ThreadApiDemo threadApiDemo = new ThreadApiDemo();
Thread t1 = new Thread(threadApiDemo);
System.out.println(t1.isAlive());//运行结果:false start前线程未活动
t1.start();
System.out.println(t1.isAlive());//运行结果:true
System.out.println(t1.getPriority()); //运行结果:10
for (int i =0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"- -"+i);
}
System.out.println(t1.isAlive());//运行结果:true
}
@Override
public void run() {
for (int i =0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"---"+i);
}
}
}
join()
package com.petrel;
/**
* @author Petrel
* @data 2020/6/28 16:47
*/
public class MyRun implements Runnable{
@Override
public void run() {
for (int i = 0;i<10;i++){
System.out.println(Thread.currentThread().getName()+i); //currentThread()方法返回正在被执行的线程的信息.
}
}
}
------------
package com.petrel;
/**
* @author Petrel
* @data 2020/6/28 16:47
*/
//join() 强制执行调用该方法的线程,其他状态处于阻塞状态 运行->阻塞
public class JoinTest {
public static void main(String[] args) {
MyRun run = new MyRun();
Thread thread = new Thread(run);
thread.start();
for (int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"--"+i);//运行结果:main--0 main--1 main--2 main--3 等线程全部运行后才会运行main--4
if (i==3){
try {
//join() 使主线程进入等待池并等待thread线程执行完毕后才会被唤醒 强制执行thread,其他状态处于阻塞状态
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/*
运行结果:
main--0
main--1
main--2
main--3
Thread-00
Thread-01
Thread-02
Thread-03
Thread-04
Thread-05
Thread-06
Thread-07
Thread-08
Thread-09
main--4
*/
sleep
package com.petrel;
/**
* @author Petrel
* @data 2020/6/28 17:19
*/
//sleep 当前执行的线程休息一段时间 进入阻塞状态
public class SleepTest {
public static void main(String[] args) {
MyRun run = new MyRun();
Thread thread = new Thread(run);
thread.start();
for (int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"- - -"+i);
if (i==2){ //如果i==2之后会进入休眠 Thread运行完后卡顿一下再运行main3和main4
try {
Thread.sleep(1000); //当前执行的线程休息一段时间 进入阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/*
运行结果: main- - -0
Thread-00
main- - -1
Thread-01
main- - -2
Thread-02
Thread-03
Thread-04
Thread-05
Thread-06
Thread-07
Thread-08
Thread-09
main- - -3
main- - -4
*/
运行->就绪
package com.petrel;
import com.petrel.MyRun;
/**
* @author Petrel
* @data 2020/6/28 20:22
*/
//运行->就绪
public class YieldTest {
public static void main(String[] args) {
MyRun run = new MyRun();
Thread thread = new Thread(run);
thread.start();
for (int i = 0;i<5;i++){
if (i==2){
Thread.yield();
System.out.println(Thread.currentThread().getName()+"- - -"+i+"礼让一次");
}else{
System.out.println(Thread.currentThread().getName()+"- - -"+i);
}
}
}
}
/*
运行结果:
main- - -0
main- - -1
main- - -2礼让一次
main- - -3
main- - -4
Thread-00
Thread-01
Thread-02
Thread-03
Thread-04
Thread-05
Thread-06
Thread-07
Thread-08
Thread-09
*/
交替输出1-10和10-1
package com.petrel.exercise;
/**
* @author Petrel
* @data 2020/6/29 9:07
*/
//交替输出1-10和10-1
public class Test1 implements Runnable{
@Override
public void run() {
for (int i=1;i<11;i++){
System.out.println(Thread.currentThread().getName()+" --- "+i);
try {
//Thread.sleep(1000); //一秒 这样不会交替轮转 睡眠时间相同 同时醒来 随机运行
Thread.sleep(1001); //多设置一点时间就可以交替轮转
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Test1 test1 = new Test1();
Thread thread = new Thread(test1);
thread.start();
for (int i = 10;i>0;i--){
System.out.println(Thread.currentThread().getName()+" - - "+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/*
运行结果:
main - - 10
Thread-0 --- 1
main - - 9
Thread-0 --- 2
main - - 8
Thread-0 --- 3
main - - 7
Thread-0 --- 4
main - - 6
Thread-0 --- 5
main - - 5
Thread-0 --- 6
main - - 4
Thread-0 --- 7
main - - 3
Thread-0 --- 8
main - - 2
Thread-0 --- 9
main - - 1
Thread-0 --- 10
*/
生产者与消费者
package com.petrel.pc;
/**
* @author Petrel
* @data 2020/6/29 10:16
*/
//生产产品,将产房放置到共享空间中
public class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
if (i%2==0){
goods.setBrand("娃哈哈");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
goods.setName("矿泉水");
}else{
goods.setBrand("旺仔");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
goods.setName("小馒头");
}
System.out.println("生产者生产了"+this.goods.getBrand()+"---"+this.goods.getName());
}
}
}
------------
package com.petrel.pc;
/**
* @author Petrel
* @data 2020/6/29 10:17
*/
//从共享空间中取走产品
public class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者取走了"+this.goods.getBrand()+"- -"+this.goods.getName());
}
}
}
------------
package com.petrel.pc;
/**
* @author Petrel
* @data 2020/6/29 10:19
*/
public class Goods {
private String brand;
private String name;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
------------
package com.petrel.pc;
/**
* @author Petrel
* @data 2020/6/29 10:31
*/
/*
* 多线程访问的时候出现了数据安全的问题
* 1、生产者没有生产商品,消费者就可以获取
* 2、商品的品牌和名称对应不上
* */
public class Test {
public static void main(String[] args) {
Goods goods = new Goods();
Producer producer = new Producer(goods);
Consumer consumer = new Consumer(goods);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
/*
运行结果:
消费者取走了娃哈哈- -矿泉水
生产者生产了娃哈哈---矿泉水
消费者取走了旺仔- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了娃哈哈- -小馒头
生产者生产了娃哈哈---矿泉水
消费者取走了旺仔- -小馒头
生产者生产了旺仔---小馒头
生产者生产了娃哈哈---矿泉水
消费者取走了娃哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
消费者取走了娃哈哈- -矿泉水
生产者生产了娃哈哈---矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了娃哈哈---矿泉水
消费者取走了旺仔- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
*/
package com.petrel.pc2.pc;
/**
* @author Petrel
* @data 2020/6/29 10:16
*/
//生产产品,将产房放置到共享空间中
public class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
if (i%2==0){
goods.set("哇哈哈","矿泉水");
}else{
goods.set("旺仔","小馒头");
}
}
}
}
------------
package com.petrel.pc2.pc;
/**
* @author Petrel
* @data 2020/6/29 10:17
*/
//从共享空间中取走产品
public class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
goods.get();
}
}
}
------------
package com.petrel.pc2.pc;
/**
* @author Petrel
* @data 2020/6/29 10:19
*/
public class Goods {
private String brand;
private String name;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//消费者获取商品
public synchronized void get(){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者取走了"+this.getBrand()+"- -"+this.getName());
}
//生产者生产商品
public synchronized void set(String brand,String name){
this.setBrand(brand);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setName(name);
System.out.println("生产者生产了"+this.getBrand()+"---"+this.getName());
}
}
------------
package com.petrel.pc2.pc;
/**
* @author Petrel
* @data 2020/6/29 10:31
*/
/*
* pc2存在的问题:1、生产者没有生产商品,消费者就可以获取
* */
public class Test {
public static void main(String[] args) {
Goods goods = new Goods();
Producer producer = new Producer(goods);
Consumer consumer = new Consumer(goods);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
/*
运行结果:
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
*/
package com.petrel.pc3.pc;
/**
* @author Petrel
* @data 2020/6/29 10:16
*/
//生产产品,将产房放置到共享空间中
public class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
if (i%2==0){
goods.set("哇哈哈","矿泉水");
}else{
goods.set("旺仔","小馒头");
}
}
}
}
------------
package com.petrel.pc3.pc;
/**
* @author Petrel
* @data 2020/6/29 10:17
*/
//从共享空间中取走产品
public class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
goods.get();
}
}
}
------------
package com.petrel.pc3.pc;
/**
* @author Petrel
* @data 2020/6/29 10:19
*/
public class Goods {
private String brand;
private String name;
//默认是不存在商品的,如果值等于true的话,代表有商品
private boolean flag = false;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//消费者获取商品
public synchronized void get(){
/*
* 如果flag等于false的话,意味着生产者没有生产商品,此时消费者无法消费,需要让消费者线程进入到阻塞状态,
* 等待生产者生产,当有商品之后,再开始消费
* */
if(!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消费者取走了"+this.getBrand()+"- -"+this.getName());
flag = false;
//唤醒生产者去生产
notify();
}
//生产者生产商品
public synchronized void set(String brand,String name){
//当生产者抢占到cpu资源之后会判断当前对象是否有值,如果有的话,以为着消费者还没有消费,需要提醒消费者消费,同时
//当前线程进入阻塞状态,等待消费者取走商品之后,再次生产,如果没有的话,不需要等待,不需要进入阻塞状态,直接生产即可
if (flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.setBrand(brand);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.setName(name);
System.out.println("生产者生产了"+this.getBrand()+"---"+this.getName());
//如果代码执行到此处,意味着已经生产完成,需要将flag设置为true
flag = true;
//唤醒消费者去消费
notify();
}
}
------------
package com.petrel.pc3.pc;
/**
* @author Petrel
* @data 2020/6/29 10:31
*/
public class Test {
public static void main(String[] args) {
Goods goods = new Goods();
Producer producer = new Producer(goods);
Consumer consumer = new Consumer(goods);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}
/*
运行结果:
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
生产者生产了哇哈哈---矿泉水
消费者取走了哇哈哈- -矿泉水
生产者生产了旺仔---小馒头
消费者取走了旺仔- -小馒头
*/
package com.petrel.pc4;
import java.util.concurrent.BlockingQueue;
/**
* @author Petrel
* @data 2020/6/29 16:32
*/
public class ProducerQueue implements Runnable{
private BlockingQueue blockingQueue;
public ProducerQueue(BlockingQueue blockingQueue){
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
Goods goods = null;
if (i%2==0){
goods = new Goods("哇哈哈","矿泉水");
}else {
goods = new Goods("旺仔","小馒头");
}
System.out.println("生产者开始生产"+goods.getBrand()+"---"+goods.getName());
try {
blockingQueue.put(goods);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
------------
package com.petrel.pc4;
import java.util.concurrent.BlockingQueue;
/**
* @author Petrel
* @data 2020/6/29 16:34
*/
public class ConsumerQueue implements Runnable {
private BlockingQueue<Goods> blockingQueue;
public ConsumerQueue(BlockingQueue blockingQueue){
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
for (int i = 0;i<10;i++){
try {
Goods goods = blockingQueue.take();
System.out.println("消费者消费的商品是:"+goods.getBrand()+"- -"+goods.getName());
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
------------
package com.petrel.pc4;
/**
* @author Petrel
* @data 2020/6/29 16:52
*/
public class Goods {
private String brand;
private String name;
public Goods(String brand, String name) {
this.brand = brand;
this.name = name;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
------------
package com.petrel.pc4;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* @author Petrel
* @data 2020/6/29 16:52
*/
public class Test {
public static void main(String[] args) {
BlockingQueue<Goods> queue = new ArrayBlockingQueue<Goods>(5);
ProducerQueue producerQueue = new ProducerQueue(queue);
ConsumerQueue consumerQueue = new ConsumerQueue(queue);
new Thread(producerQueue).start();
new Thread(consumerQueue).start();
}
}