线程复习

1. 线程的休眠

需求:编写一个抽取学员回答问题的程序,要求倒数三秒后输出被抽中的学员姓名

分析:

1. 创建String数组存放学员姓名

2. 利用随机数获取学员下标

3. 通过下标获取学员姓名

4. 倒计时3秒通过for循环使用Thread.sleep(1000)来实现,

Thread.sleep(1000);此方法为静态方法,写在哪个线程中,哪个线程就休眠

package com.wz.thread06;

import java.util.Random;

public class test01 {
    /**
     * 知识点:线程的休眠
     * 需求:编写一个抽取学员回答问题的程序
     * 要求倒数三秒后输出被抽中的学员姓名
     */
    public static void main(String[] args) throws InterruptedException {
        //创建String数组存放学员姓名
        String[] names = {"张三","李四","王五","赵六","AAA","BBB","CCC"};
        //利用随机数获取学员下标
        Random random = new Random();
        int index = random.nextInt(names.length);
        //倒计时3秒通过for循环使用Thread.sleep(1000)来实现
        for (int i = 3; i >=1 ; i--) {
            System.out.println(i);
            Thread.sleep(1000);
        }
        //通过下标获取学员姓名
        System.out.println("抽到的学员是:"+names[index]);
    }
}

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_生产者消费者模型

2. 线程的礼让

需求:创建两个线程A,B,分别各打印1-100的数字,其中B一个线程,每打印一次,就礼让一次,观察实验结果

分析:

1. 创建A线程,继承Thread,重写run方法,打印1-100的数字

2. 创建B线程,继承Thread,重写run方法,打印1-100的数字,每打印一次,就礼让一次

Thread.yield();

此方法为静态方法,此方法写在哪个线程中,哪个线程就礼让

所谓的礼让是指当前线程退出CPU资源,并转到就绪状态,接着再抢

package com.wz.thread07;

public class A extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <=100 ; i++) {
            System.out.println("A线程"+i);
        }
    }
}
package com.wz.thread07;

public class B extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <=100 ; i++) {
            System.out.println("B线程"+i);
            Thread.yield();
        }
    }
}
package com.wz.thread07;

public class test01 {
    /**
     * 需求:创建两个线程A,B
     * 分别各打印1-100的数字
     * 其中B一个线程,每打印一次,就礼让一次,观察实验结果
     */
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.start();
        b.start();
    }
}

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_线程生命周期_02

3. 线程的合并

需求:主线程和子线程各打印200次,从1开始每次增加1,当主线程打印到10之后,让子线程先打印完再打印主线程

分析:

1. 创建主线程,打印1~200

2. 创建子线程,打印1~200

3. 判断当主线程打印到10,用join()方法将子线程加入主线程

t.join(); 合并方法

package com.wz.thread08;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 1; i <=200 ; i++) {
            System.out.println("子线程"+i);
        }
    }
}
package com.wz.thread08;

public class test01 {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        for (int i = 1; i <=200 ; i++) {
            System.out.println("主线程"+i);
            if (i>10){
                myThread.join();
            }
        }
    }
}

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_线程合并_03

4. 线程的中断

  1. stop();立即终止,该方法已经过时。无法保证功能的完整性
  2. run()执行完毕,利用boolean值来控制线程的中断
  3. interrupt();中断这个线程(改变线程状态)

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_线程合并_04

package com.wz.thread09;

public class MyThread extends Thread{
    @Override
    public void run() {
        //判断当前线程是否消亡(True-消亡 false- 未消亡)
        while (!Thread.currentThread().isInterrupted()){
            System.out.println("AAAA");
            System.out.println("BBBB");
            System.out.println("CCCC");
            System.out.println("DDDD");
            System.out.println("EEEE");
            System.out.println(Thread.currentThread().isInterrupted());
        }
    }
}
package com.wz.thread09;

public class test01 {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        myThread.sleep(5000);
        //改变线程状态,开始为false(未消亡)--> 调用后 True(消亡)
        myThread.interrupt();
    }
}

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_线程的休眠_05

5. 后台线程(守护线程)

守护线程 默默守护着前台线程,当所有的前台线程都消亡后,守护线程会自动消亡

注意:垃圾回收器就是守护线程

t.setDaemon(true);

package com.wz.thread10;

public class A extends Thread{
    @Override
    public void run() {
        while (true){
            System.out.println("后台线程守护着前台线程!");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
package com.wz.thread10;

public class test01 {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        a.setDaemon(true);
        a.start();
        for (int i = 1; i <=20 ; i++) {
            System.out.println("前台线程"+i);
            Thread.sleep(1000);
        }
    }
}

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_生产者消费者模型_06

/**
	 * 重写
	 * 概念:父类方法在子类中重新写一遍
	 * 应用场景:父类方法不满足子类需求,考虑在子类中重写父类的方法
	 * 条件:
	 * 		1.在子类中重写
	 * 		2.返回值、方法名、参数列表、抛出异常类型必须和重写父类的方法的一致
	 * 		3.访问修饰符不能比父类更加严格
	 */

6. 线程的生命周期

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_线程合并_07

生产者消费者模型

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_生产者消费者模型_08

创建产品类(Phone)

package producer_consumer_01;

//产品类
public class Phone {

    private String brand;//品牌
    private double price;//价格
    private boolean store;//仓库-false空

    public Phone() {
    }

    public Phone(String brand, double price) {
        this.brand = brand;
        this.price = price;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public boolean isStore() {
        return store;
    }

    public void setStore(boolean store) {
        this.store = store;
    }

    @Override
    public String toString() {
        return "Phone [brand=" + brand + ", price=" + price + "]";
    }
}

创建生产者线程Producer extends Thread,重写run()方法

package producer_consumer_01;

//生产者线程
public class Producer extends Thread{

    private Phone phone;

    public Producer(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void run() {

        boolean flag = true;

        while(true){
            //加锁
            synchronized (phone) {
                if(phone.isStore()){
                    try {
                        phone.wait();//等待:1.将等待的线程记录在对象监视器中 2.释放锁资源 3.让当前线程进入到阻塞状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(flag){
                    phone.setBrand("华为");
                    phone.setPrice(3999);
                }else{
                    phone.setBrand("小米");
                    phone.setPrice(1999);
                }
                flag = !flag;
                phone.setStore(true);

                phone.notify();//唤醒:唤醒的对象监视器中随机的一个线程
            }
        }
    }
}

创建消费者线程 Consumer extends Thread,重写run()方法

package producer_consumer_01;

//消费者线程
public class Consumer extends Thread{

    private Phone phone;

    public Consumer(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void run() {
        while(true){
            synchronized(phone){
                if(!phone.isStore()){
                    try {
                        phone.wait();//等待:1.将等待的线程记录在对象监视器中 2.释放锁资源 3.让当前线程进入到阻塞状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(phone.getBrand() + " -- " + phone.getPrice());
                phone.setStore(false);

                phone.notify();//唤醒:唤醒:唤醒的对象监视器中随机的一个线程
            }
        }
    }
}

测试类

package producer_consumer_01;

public class test01 {
    /**
     * 知识点:生产者消费者模型
     * 分析:
     * 		产品类
     * 		生产者线程不断的生产产品(set())
     * 		消费者线程不断的消费产品(get())
     *
     * 情况:一个生产者一个消费者的情况
     * 最终目的:生产一个、消费一个
     *
     * 步骤:
     * 		1.让生产者消费者线程操作同一个资源(产品对象)
     * 			bug:
     */
    public static void main(String[] args) {

        Phone phone = new Phone();

        Producer p = new Producer(phone);
        Consumer c = new Consumer(phone);

        p.start();
        c.start();
    }
}

2023年7月5日,生产者消费者模型,线程的休眠、礼让、合并、中断、生命周期、守护线程_生产者消费者模型_09