狂神-线程笔记

线程

重点:线程的实现、线程同步

1、线程简介

一个进程有多个线程

 2、实现

thread 继承thread类、实现runnable接口、实现callable

public class TestThread01 extends Thread{
    /**
     * 方式1:继承Threa类,重新run()方法,调用start()
     * 总结:
     *  线程开启不一定是立即执行,是由CPU决定调度执行
     */
    @Override
    public void run() {
        //线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("小玉玉喜欢吃肉肉~~~~"+i);
        }
    }
    public static void main(String[] args) {
        //调用
        TestThread01 testThread01 = new TestThread01();
        testThread01.start();
        //testThread01.start();这个是俩个线程是交替进行的
        //testThread01.run();这个是走的单线程,先走的是run方法的内容
        for (int i = 0; i < 2000; i++) {
            System.out.println("小绿喜欢吃白菜~~~"+i);
        }
    }
}

练习多线程下载文件

public class TestThread02 extends Thread{
    private  String url;
    private  String fileName;
    private  String inThread;

    public TestThread02(String url, String fileName, String inThread) {
        this.url = url;
        this.fileName = fileName;
        this.inThread=inThread;
    }
    //调用线程
    public static void main(String[] args) {
        TestThread02 t1 = new TestThread02("https://i0.hdslb.com/bfs/sycp/creative_img/202107/23d0390e2abd49a9b0cf3df55c4e7648.jpg", "1.jpg", "1");
        TestThread02 t2 = new TestThread02("https://i0.hdslb.com/bfs/sycp/creative_img/202101/8b0e68d45dae53febbef907bdb4e61fe.jpg", "2.jpg", "2");
        TestThread02 t3 = new TestThread02("https://i0.hdslb.com/bfs/sycp/creative_img/202110/95c7a7b3cf5a7f22b38f7e675443a16d.jpg", "3.png", "3");

        t1.start();
        t2.start();
        t3.start();
    }

    //线程体
    @Override
    public void run() {

        downLoad(url,fileName);
        System.out.println("当前线程"+inThread);
    }

    //下载文件的方法
    public void downLoad(String url,String fileName){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(fileName));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

实现callable接口,推荐使用,因为java是单继承的会出现问题

// 方式2 实现 Runnable接口 推荐使用的方式
public class TestThread03 implements Runnable {

    @Override
    public void run() {
        //线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("小玉玉喜欢吃肉肉~~~~"+i);
        }
    }
    public static void main(String[] args) {
       //调用
        TestThread03 t1 = new TestThread03();
        TestThread03 t2 = new TestThread03();
        new Thread(t1).start();
        new Thread(t2).start();
        for (int i = 0; i < 2000; i++) {
            System.out.println("小绿喜欢吃白菜~~~"+i);
        }
    }
}

 多线程实现龟兔赛跑案例

public class Race implements Runnable {

    //打印胜利者
   private static String winner;

    public static void main(String[] args) {
        Race race=new Race();
        //一条赛道
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }

    @Override
    public void run() {

        for (int i = 0; i <= 100; i++) {
            //模拟兔子休息
            if(Thread.currentThread().getName().equals("兔子")&& i%20==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            //判断比赛是否结束
            boolean flag=isEnd(i);
            if (flag){
                //比赛结束停止比赛
                break;
            }
            System.out.println(Thread.currentThread().getName()+"----->跑了"+i+"步");

        }
    }


//判断是否完成比赛
    private boolean isEnd(int step){
        if (winner!=null){
            //已经有胜利者
            return true;
        }{
            if (step>=100){
                //步数是100到达终点
                winner=Thread.currentThread().getName();
                System.out.println("Winner is"+winner);
                return  true;
            }
        }
        return false;
    }
}

 静态代理模式

/**
 *代理结婚的案例说明静态代理模式
 * 静态代理模式总结
 * 真实对象和嗲了对象都要实现一个接口
 * 代理对象要代理真实角色
 *
 * 好处:
 * 代理对象可以做很多真实对象做不了的事情
 * 代理对象专注做自己的事情
 *
 * @author xiaoxiaoyu
 * @create 2021/11/2
 * @since 1.0.0
 */
public class StaticProxy {
    public static void main(String[] args) {
        //
//        new Thread(()->{ System.out.println("I love you"); }).start();

        //thread代理真实对象
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("I love you");
            }
        }).start();

       new WeddingCompany(new You()).HappyMarry();

    }
}

interface  Marry{

    void HappyMarry();
}

class You implements Marry{
    //真实角色,你去结婚

    @Override
    public void HappyMarry() {
        System.out.println("小玉玉结婚啦~~~");
    }
}

class WeddingCompany implements Marry{
    //代理角色  婚庆公司帮你结婚


    //代理谁---->真实目标角色
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        //前期准备工作
        befor();
        target.HappyMarry();
        //后期收尾工作
        afters();
    }

    private void befor() {
        System.out.println("结婚前,布置现场");
    }

    private void afters() {
        System.out.println("结婚后,收尾工作");
    }
}

 Lamda表达式

public class TestLambda1 {

    //3.静态内部类
   static class Love2 implements Ilove{
        @Override
        public void love(int i) {
            System.out.println("i love you--->"+i);
        }
    }

    public static void main(String[] args) {
        Ilove ilove=null;
        ilove= new Love2();
        ilove.love(2);

        //4内部类
        class Love3 implements Ilove{
            @Override
            public void love(int i) {
                System.out.println("i love you--->"+i);
            }
        }
         ilove= new Love3();
        ilove.love(3);

        //5,匿名内部类:没有类的名称,必须借助接口或者是父类
        ilove=new Ilove() {
            @Override
            public void love(int i) {
                System.out.println("i love you--->"+i);
            }
        };
        ilove.love(4);

        //6、用lambda简化
        /*
        *总结:
        *   lambda代码只有一行的时候,才能简化为一行,如果有多行,那么就用代码块包裹
        *   前提是接口是函数式接口
        *   多个参数也可以去掉参数类型,去掉就都去掉,必须加上括号
        * */
        ilove=(int i)-> {
            System.out.println("i love you--->"+i);
        };
        ilove.love(5);
    }

}
//1,定义个函数式接口:接口中只有一个方法
interface Ilove{
    void love(int i);
}

//2,实现类
class Love implements Ilove{
    @Override
    public void love(int i) {
        System.out.println("i love you--->"+i);
    }
}

线程状态:

新生状态---》就绪状态(start)--》 运行状态(run)------》阻塞状态(sleep、wait)-----》死亡状态deal()

1、测试stop线程

/**
 * 〈测试线程停止〉
 *  1、建议线程正常停止=====》利用次数,不建议死循环
 *  2、建议使用标志位 flag
 *  3、不要使用stop或者是destory等过时的方法或者JDK不建议使用的方法
 * @author xiaoxiaoyu
 * @create 2021/11/4
 * @since 1.0.0
 */
public class TestStop implements Runnable {

    private boolean flag=true;
    @Override
    public void run() {
       int i = 0;
       while (flag){
           System.out.println("runn。。thread"+i++);
       }
    }
    //在对外写一个停止的方法

    public void stopThread(){
        this.flag=false;
    }

    public static void main(String[] args) {
        //创建线程
        TestStop testStop =new TestStop();
        new Thread(testStop).start();


        for (int i = 0; i < 1000; i++) {
            System.out.println("main线程"+i);
            if (i==900){
                testStop.stopThread();
                System.out.println("该停止啦");
            }
        }
    }
}

2、测试sleep

/**
 * 没有对象都有一把锁,sleep不会释放锁
 * @author xiaoxiaoyu
 * @create 2021/11/4
 * @since 1.0.0
 */
public class TestSleep  {
    public static void main(String[] args)throws Exception {
        //案例1:模拟倒计时
//        tenDown();
        //案例2:打印当前系统时间
        Date date = new Date(System.currentTimeMillis());//当前系统时间
        while (true){
            System.out.println(new SimpleDateFormat("HH-mm-ss").format(date));
            Thread.sleep(1000);

            date= new Date(System.currentTimeMillis());//当前系统时间
        }
    }
    //倒计时的方法
    public static void tenDown(){
        int i=10;
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(i--);
                if (i<=0){
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3、 线程礼让:yield 已让不一定能成功,看cpu心情,礼让之后会进入到就绪状态,重新进行竞争

4、线程join:相当于是插队,待此线程执行完成后其他线程才能执行,其他线程阻塞

public class TestJoin implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我是VIP"+i);
        }
    }

    public static void main(String[] args) throws Exception{
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();

        for (int i = 0; i < 10; i++) {
            if (i==5){
                //插队,不建议使用,会造成阻塞
                thread.join();
            }
            System.out.println("main"+i);
        }
    }
}

5、线程状态

public class TestThreadState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            System.out.println("----------------");
        });

        Thread.State state = thread.getState();
        System.out.println(state);
        //NEW

        thread.start();
        state = thread.getState();
        System.out.println(state);
        //启动线程

        while (state!=Thread.State.TERMINATED){
            //只要线程不终止就一直输出
            Thread.sleep(100);
            //更新状态
            state = thread.getState();
            System.out.println(state);
        }

        //死亡后的线程不能再次进行启动
//        thread.start();
    }
}

6、线程优先级

public class TestThreadProprity  {
    public static void main(String[] args) {
        //主线程的优先级
        System.out.println(Thread.currentThread().getName()+"----->"+Thread.currentThread().getPriority());

        MyProprity myProprity= new MyProprity();
        Thread t1 = new Thread(myProprity);
        Thread t2 = new Thread(myProprity);
        Thread t3 = new Thread(myProprity);

        //启动前进行设置优先级
        t1.setPriority(3);
        t1.start();

        t2.start();

        t3.setPriority(9);
        t3.start();
        //优先级高的不一定先执行,看CPU的心情,但是优先级高的执行的概率大一点
    }

}
class  MyProprity extends Thread{
    @Override
    public void run() {
        //获取优先级
        System.out.println(Thread.currentThread().getName()+"----->"+Thread.currentThread().getPriority());
    }
}

7、守护线程

public class TestThreadDaemon {
    public static void main(String[] args) {
        God god = new God();
        Thread thread = new Thread(god);
        //默认是false  设置true为守护线程
        thread.setDaemon(true);
        thread.start();

        new Thread(new Yous()).start();

        /**
         * 总结:
         * 线程分为守护线程和用户线程(普通线程)
         * 虚拟机必须确保用户线程执行完毕
         * 虚拟机不用等待守护线程执行完毕
         * 比如:后台操作日志、垃圾回收
         */
    }
}
class God implements Runnable{
    @Override
    public void run() {
       while (true){
           System.out.println("上帝在守护着你。。。。。。");
       }
    }
}
class  Yous implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("---开开心心活着--");
        }
        System.out.println("===good bye! world=======");
    }
}

  2、线程同步

2.1线程不安全案例:买票

public class UnsafeBuyTicket {
//线程不安全,有负数
    public static void main(String[] args) {
        //因为是多个线程操作的是同一个资源,所以需要new 一份
        BuyTick statics = new BuyTick();

        new Thread(statics,"A").start();
        new Thread(statics,"B").start();
        new Thread(statics,"C").start();
        new Thread(statics,"D").start();
    }
}

class BuyTick implements Runnable{

    //票数
    private  int tickNum=10;
    //线程终止,用falg
    Boolean flag=true;
    @Override
    public void run() {
        //买票
        while (flag){
            try {
                tick();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    private void tick() throws InterruptedException {
        if (tickNum<=0){
            //没有票了
           this.flag=false;
           return;
        }
        Thread.sleep(1000);

        //有票
        System.out.println(Thread.currentThread().getName()+"----->"+tickNum--);
    }
}

2.2线程不安全案例;取钱

 

//两个人去银行取钱,账户
    //线程的内存都是各自处理的,都是从100这里拷贝过去的

public class UnsafeBank {
    public static void main(String[] args) {
        //账户
        Account account=new Account(100,"结婚基金");
        Drawing you = new Drawing(account, 50, "you");
        Drawing grilFriend = new Drawing(account, 100, "grilFriend");
        you.start();
        grilFriend.start();
    }
}
//账户
class Account {
    //余额
      int money;
    //卡名
     String name;
    public Account(int money,String name){
    this.money=money;
    this.name=name;
    }
}

//银行:模拟取款:不涉及都多个线程操作同一个对象
class Drawing extends Thread{
    Account account;
    //取了多少钱
    int drawingMoney;
    //现在手里有多少钱
    int nowMoney;
    public Drawing( Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
   //取钱
    public void GetMoney(){
        if (account.money-drawingMoney<0){
            System.out.println(Thread.currentThread().getName()+"----余额不足---");
            return;
        }
        //放大问题的发生性
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //卡内余额=余额-你取走的钱
        account.money=account.money-drawingMoney;
        //你手里的钱
        nowMoney=nowMoney+drawingMoney;
        //this.getName()=  Thread.currentThread().getName()
        System.out.println(account.name+"账户余额:"+account.money);
        System.out.println(this.getName()+"手里的钱有:"+nowMoney);
    }
    @Override
    public void run() {
        GetMoney();
    }
}

3、不安全的集合

public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String > list=new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(1000);
        System.out.println(list.size());
    }
}

 将线程不安全的案例变为线程安全的案例

锁的这个对象,一定是进行增删改查的对象

买票

public class UnsafeBuyTicket {
    //线程不安全,有负数
    public static void main(String[] args) {
        //因为是多个线程操作的是同一个资源,所以需要new 一份
        BuyTick statics = new BuyTick();

        new Thread(statics,"A").start();
        new Thread(statics,"B").start();
        new Thread(statics,"C").start();
        new Thread(statics,"D").start();
    }
}

class  BuyTick implements Runnable{

    //票数
    private  int tickNum=10;
    //线程终止,用falg
    Boolean flag=true;
    @Override
    public void run() {
        //买票
        while (flag){
            try {
                tick();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
    //synchronized(this)=BuyTick锁定的是类本身
    private synchronized void tick() throws InterruptedException {
        if (tickNum<=0){
            //没有票了
           this.flag=false;
           return;
        }
        Thread.sleep(1000);

        //有票
        System.out.println(Thread.currentThread().getName()+"----->"+tickNum--);
    }
}

取钱

public class UnsafeBank {
    public static void main(String[] args) {
        //账户
        Account account=new Account(1000,"结婚基金");
        Drawing you = new Drawing(account, 50, "you");
        Drawing grilFriend = new Drawing(account, 100, "grilFriend");
        you.start();
        grilFriend.start();
    }
}
//账户
class Account {
    //余额
      int money;
    //卡名
     String name;
    public Account(int money,String name){
    this.money=money;
    this.name=name;
    }
}

//银行:模拟取款:不涉及都多个线程操作同一个对象
class Drawing extends Thread{
    Account account;
    //取了多少钱
    int drawingMoney;
    //现在手里有多少钱
    int nowMoney;
    public Drawing( Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }
   //取钱
    public void GetMoney(){
        synchronized (account){
            if (account.money-drawingMoney<0){
                System.out.println(Thread.currentThread().getName()+"----余额不足---");
                return;
            }
            //放大问题的发生性
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //卡内余额=余额-你取走的钱
            account.money=account.money-drawingMoney;
            //你手里的钱
            nowMoney=nowMoney+drawingMoney;
            //this.getName()=  Thread.currentThread().getName()
            System.out.println(account.name+"账户余额:"+account.money);
            System.out.println(this.getName()+"手里的钱有:"+nowMoney);
        }

    }
    @Override
    public void run() {
        GetMoney();
    }
}

  ArrayList

public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String > list=new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                synchronized(list){
                    list.add(Thread.currentThread().getName());
                }

            }).start();
        }
        Thread.sleep(3000);
        System.out.println(list.size());
    }
}

或者是使用的是JUC下的包

import java.util.concurrent.CopyOnWriteArrayList;
public class TestJUC {

    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayList<String > copyOnWriteArrayList=new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                copyOnWriteArrayList.add(Thread.currentThread().getName());
            }).start();
        }
        Thread.sleep(3000);
        System.out.println(copyOnWriteArrayList.size());
    }
}

3、死锁

//死锁:多个线程互相抱着对方需要的资源进行僵持
public class TestDealLock {
    public static void main(String[] args) {
        new Thread(new Deal2(0,"灰姑娘")).start();
        new Thread(new Deal2(1,"白雪公主")).start();
        /**
         * 打印结果
         * 灰姑娘拿到了口红的锁
         * 白雪公主拿到了镜子的锁
         * 导致死锁原因:
         * 1、互斥条件
         * 2、请求与保持
         * 3、不剥夺条件
         * 4、循环条件
         * 只要是不满足其中一条就不会造成死锁的现象
         */
        /**
         * 优化后打印结果
         * 灰姑娘拿到了口红的锁
         * 白雪公主拿到了镜子的锁
         * 白雪公主拿到了口红的锁
         * 灰姑娘拿到了镜子的锁
         */
    }

}
//口红
class Lipsti{

}
//镜子
class Mirror{

}

class  Deal2 implements Runnable {
    //独一份的资源
   private static Lipsti lipsti=new Lipsti();
   private static Mirror mirror=new Mirror();
   private  String  name;
   private int choice;

   public Deal2(int choice,String name){
       this.choice=choice;
       this.name=name;
   }
    @Override
    public void run() {

    if (choice==0){
        synchronized (lipsti){
            System.out.println(name+"拿到了口红的锁");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //会造成死锁
//            synchronized (mirror){
//                System.out.println(name+"拿到了镜子的锁");
//            }
        }
        //优化后,不会产生死锁
        synchronized (mirror){
            System.out.println(name+"拿到了镜子的锁");
        }
    }else {
        synchronized (mirror){
            System.out.println(name+"拿到了镜子的锁");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //会造成死锁
//            synchronized (lipsti){
//                System.out.println(name+"拿到了口红的锁");
//            }
        }
        //优化后,不会产生死锁
         synchronized (lipsti){
                System.out.println(name+"拿到了口红的锁");
            }
    }
    }
}

Lock和Synchronize的区别

public class TestLock {
    /**
     *总结Lock和Synchronize的区别
     * 1、Lock是显示锁(手动进行开关),synchronize是隐式锁
     * 2、Lock没有代码块和方法锁,synchronize有
     * 3、Lock是JVm的,性能更好一点,有扩展性
     * 4、优先使用顺序
     * Lock》同步代码块》同步代码方法
     * */

    public static void main(String[] args) {
        BuyTick1 buyTick1 = new BuyTick1();
        new Thread(buyTick1).start();
        new Thread(buyTick1).start();
        new Thread(buyTick1).start();
    }
}
//买票的案例
class BuyTick1 implements Runnable{
    //可重入锁
   static ReentrantLock reentrantLock=new ReentrantLock();

    int ticlNum=10;
    @Override
    public void run() {
        try {
            reentrantLock.lock();
            while (true){
                if (ticlNum<=0){
                    break;
                }
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(ticlNum--);
            }

        }finally {
            reentrantLock.unlock();
        }
    }
}

 线程通讯:使用wait和notify

管程法解决生产者和消费者问题

//生产者、消费者、产品、缓冲区   ---->管程法:利用缓冲区
public class TestPC {

    public static void main(String[] args) {
        SynContainet containet=new SynContainet();
        new Thread(new Proctor(containet)).start();
        new Thread(new Cutors(containet)).start();
    }


}

class Proctor implements Runnable{
    SynContainet containet;

    public Proctor(SynContainet containet) {
        this.containet = containet;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            containet.push(new Chick(i));
            System.out.println("生产了"+i+"只鸡");
        }

    }
}

class Cutors implements Runnable{

    SynContainet containet;

    public Cutors(SynContainet containet) {
        this.containet = containet;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了"+containet.pop().id+"只鸡");
        }
    }
}

class Chick {
    int  id;

    public Chick(int id) {
        this.id = id;
    }
}

class SynContainet{

    //缓冲区大小
    Chick[] chicks=new Chick[10];
    int count = 0;

    public synchronized void push(Chick chick){
    //生产者
        //判断能不能存
        if(count==chicks.length){
        //生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //没有生产满,就需要丢入产品
        chicks[count]=chick;
        count++;
        //通知消费者去消费
        this.notifyAll();
    }

    //消费者
    public synchronized  Chick pop(){
        if (count==0){
            try {
                //消费者等待
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //消费者去消费
        count--;
        Chick chick = chicks[count];
        //通知生产者生产
        this.notifyAll();
        return chick;
    }
}

生产者和消费者解决方法2:信号灯发 :核心就是定义一个标志位

/**
 * 〈一句话功能简述〉<br> 
 * 〈信号灯法解决生产者和消费者问题:定义一个flag〉
 * @author xiaoxiaoyu
 * @create 2021/11/9
 * @since 1.0.0
 */
public class TestPC2 {
    public static void main(String[] args) {
        Perform perform=new Perform();
        new Thread(new Player(perform)).start();
        new Thread(new Watcher(perform)).start();
    }
}
//演员
class Player implements Runnable{
    Perform perform;
    public Player(Perform perform) {
        this.perform = perform;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i%2==0){
                //表演
                perform.play("斗罗大陆**");
            }else {
                perform.play("广告time。。。");
            }
        }
    }
}
//观众
class Watcher implements Runnable{
    Perform perform;

    public Watcher(Perform perform) {
        this.perform = perform;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
           perform.watch();
        }
    }
}
//表演
class Perform{
    String dance;
    boolean flag=true;
    //true:演员表演,观众等待
    //演员表演
    public synchronized void play(String dance){
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演节目:"+dance);
        //通知观众观看
        this.notifyAll();
        this.dance=dance;
        this.flag=!this.flag;
    }
    public synchronized void  watch(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看"+dance);
        //通知演员表演
        this.notifyAll();
        this.flag=!this.flag;
    }
}

 

posted @ 2021-10-30 20:56  白小纯~  阅读(133)  评论(0)    收藏  举报