java基础入门---多线程

1、线程简介

普通方法调用和多线程比较:

在这里插入图片描述

进程(Process)、线程(Thread)
  • 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个今天的概念。
  • 进程是执行程序的一次执行过程,它是一个动态概念。是系统资源分配的单位。
  • 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程。线程是CPU调度和执行的单位。

**注意:**很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错局。

概念总结
  • 线程就是独立的执行路径。
  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程、gc线程。
  • main()称之为主线程,为系统的入口,用于执行整个程序。
  • 在一个进程中,如果开辟了多个线程,线程的运行由(CPU)调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的。
  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。
  • 线程会带来额外的开销,如CPU调度时间,并发控制开销。
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。

2、线程实现

线程的三种创建方式:
  • Thread class---------->继承Thread类
//创建线程方式之一:  继承Thread类   重写run方法  调用start开启线程
public class TestThreadDemo01 extends Thread{

    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程---"+i);
        }
    }


    public static void main(String[] args) {
        //main()线程  主线程

        //创建一个线程对象
        TestThreadDemo01 testThreadDemo01 = new TestThreadDemo01();
        //调用start()方法开启线程
        testThreadDemo01.start();//连个线程同时运行
        //testThreadDemo01.run();//会按照先后顺序执行

        for (int i = 0; i < 1000; i++) {
            System.out.println("I like reading---"+i);
        }
    }
}

练习:实现网络图片下载

// 首先要下载commons-io-2.10.jar这个包才可以
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread  实现多线程同时下载图片
public class TestThreadDemo02 extends Thread{

    private String url;
    private String name;

    public TestThreadDemo02(String url, String name) {
        this.url = url;
        this.name = name;
    }
    //下载图片的线程体
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载的图片是:"+name);
    }

    public static void main(String[] args) {

        TestThreadDemo02 threadDemo1 = new TestThreadDemo02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2F2c.zol-img.com.cn%2Fproduct%2F124_500x2000%2F748%2FceZOdKgDAFsq2.jpg&refer=http%3A%2F%2F2c.zol-img.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626443878&t=bd893d4e852ae2792b563667c0146b21","1.jpg");
        TestThreadDemo02 threadDemo2 = new TestThreadDemo02("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic11.nipic.com%2F20101209%2F4394820_003423992807_2.jpg&refer=http%3A%2F%2Fpic11.nipic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626444051&t=5c03a0e39a5982712edbb4559c6518dd","2.jpg");
        TestThreadDemo02 threadDemo3 = new TestThreadDemo02("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=290629852,2245493184&fm=26&gp=0.jpg","3.jpg");

        //同时进行 不分先后
        threadDemo1.start();
        threadDemo2.start();
        threadDemo3.start();
    }


}
//工具类   下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • Runnable接口---------->实现Runnable接口
//创建线程方式2:  实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start开启线程
public class RunnableDemo01 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习多线程---"+i);
        }
    }

    public static void main(String[] args) {
        //创建runnable接口的实现类对象
        RunnableDemo01 runnableDemo01 = new RunnableDemo01();
        //创建线程对象,通过线程对象来开启我们的线程,代理

//        Thread thread = new Thread(runnableDemo01);
//        thread.start();

        new Thread(runnableDemo01).start();//同时运行

        for (int i = 0; i < 1000; i++) {
            System.out.println("I like reading---"+i);
        }
    }
}

线程不安全实例:

//多个线程同时操作一个对象
//火车票的实例
//问题:多个线程同时操作一个对象,线程不安全,数据紊乱!
public class RunnableDemo02 implements Runnable {

    private int ticketNum=10;

    @Override
    public void run() {
        while (true){
            if (ticketNum<=0){
                break;
            }
            //模拟延时
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNum--+"张票");
        }
    }

    public static void main(String[] args) {
        RunnableDemo02 runnableDemo02 = new RunnableDemo02();

        new Thread(runnableDemo02,"小李子").start();
        new Thread(runnableDemo02,"小郭子").start();
        new Thread(runnableDemo02,"盗版").start();
    }

}

多线程案例–龟兔赛跑:

//模拟龟兔赛跑
public class Race implements Runnable{

    //胜利者
    private static String winner;
    @Override
    public void run() {
        for (int i = 0; i <= 1000; i++) {//i 表示步数
            //模拟判断兔子休息   党每过10步且是兔子的时候 兔子就会休息
            if (Thread.currentThread().getName().equals("兔子") && i%100==0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //判断比赛是否结束
            boolean flag=gameOver(i);
            //比赛结束就停止
            if (flag){
                break;
            }

            System.out.println(Thread.currentThread().getName()+"--->跑了"+i+"步");

        }
    }

    //判断是否完成比赛
    private boolean gameOver(int steps){
        //判断是否有胜利者
        if (winner!=null){//说明胜利者已经产生
            return true;
        }{
            if (steps>=1000){
                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();
    }

}

  • Callable接口------------>实现Callable接口

步骤如下:

  1. 实现Callable接口,需要返回值类型
  2. 重写call方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);
  5. 提交执行:Future result1=ser.submit(t1);
  6. 获取结果:boolean r1=result1.get();
  7. 关闭服务:ser.shutdownNow();

实例演示下载图片:

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class TestCallable implements Callable<Boolean> {
    private String url;
    private String name;

    public TestCallable(String url, String name) {
        this.url = url;
        this.name = name;
    }
    //下载图片的线程体
    @Override
    public Boolean call() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载的图片是:"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        TestCallable threadDemo1 = new TestCallable("https://gimg2.baidu.com/image_search/src=http%3A%2F%2F2c.zol-img.com.cn%2Fproduct%2F124_500x2000%2F748%2FceZOdKgDAFsq2.jpg&refer=http%3A%2F%2F2c.zol-img.com.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626443878&t=bd893d4e852ae2792b563667c0146b21","4.jpg");
        TestCallable threadDemo2 = new TestCallable("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic11.nipic.com%2F20101209%2F4394820_003423992807_2.jpg&refer=http%3A%2F%2Fpic11.nipic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1626444051&t=5c03a0e39a5982712edbb4559c6518dd","5.jpg");
        TestCallable threadDemo3 = new TestCallable("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=290629852,2245493184&fm=26&gp=0.jpg","6.jpg");

        //1. 创建执行服务
        ExecutorService ser= Executors.newFixedThreadPool(3);
        //2. 提交执行
        Future<Boolean> result1=ser.submit(threadDemo1);
        Future<Boolean> result2=ser.submit(threadDemo2);
        Future<Boolean> result3=ser.submit(threadDemo3);
        //3. 获取结果
        boolean r1=result1.get();
        boolean r2=result2.get();
        boolean r3=result3.get();
       // 4. 关闭服务
        ser.shutdownNow();

    }


}
//工具类   下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Thread和Runnable比较:
在这里插入图片描述

静态代理对比Thread:

原则:

  • 真实对象和代理对象都要实现同一个接口。
  • 代理对象要代理真实的角色。
//实例结婚模拟代理对象
public class ProxyStatic {
    public static void main(String[] args) {

        WeddingCompany weddingCompany = new WeddingCompany(new You());
        weddingCompany.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() {
        before();
        this.target.HappyMarry();//结婚
        after();

    }

    private void before() {
        System.out.println("结婚之前,先煮羊!!!");
    }
    private void after() {
        System.out.println("结婚之后,开始吃羊!!!");
    }

}
Lambda表达式:符号–>(“λ”)

学习Lambda表达式是函数式接口的关键

函数式接口定义:

  • 任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
  • 可以通过lambda表达式来创建改接口的对象。
//推导lambda表达式
public class TestLambda01 {

    //2.静态内部类实现
   static class MyLambda2 implements ILambda{
        @Override
        public void show() {
            System.out.println("Lambda表达式输出完毕!!!MyLambda2");
        }
    }
    public static void main(String[] args) {

        //1.外部类直接实现
        ILambda lambda=new MyLambda1();//接口new实现类
        lambda.show();

        System.out.println("==================");

        lambda=new MyLambda2();
        lambda.show();

        System.out.println("==================");

        //3.局部内部类
        class MyLambda3 implements ILambda{
            @Override
            public void show() {
                System.out.println("Lambda表达式输出完毕!!!MyLambda3");
            }
        }
        lambda=new MyLambda3();
        lambda.show();

        System.out.println("==================");

        //4.匿名内部类  没有类的名称 必须借助接口或者父类
        lambda=new ILambda() {
            @Override
            public void show() {
                System.out.println("Lambda表达式输出完毕!!!MyLambda4");
            }
        };
        lambda.show();

        System.out.println("==================");

        //5.简化Lambda表达式
        lambda=()->{
            System.out.println("Lambda表达式输出完毕!!!MyLambda5");
        };
        lambda.show();
    }

}

//定义一个函数式接口
interface ILambda{
    void show();
}

//接口实现类
class MyLambda1 implements ILambda{
    @Override
    public void show() {
        System.out.println("Lambda表达式输出完毕!!!MyLambda1");
    }
}

化简Lambda表达式:

//化简Lambda表达式
public class TestLambda02 {

    public static void main(String[] args) {
        ILove love = null;

        love=(a,b,name)->{
            System.out.println("灰太狼大概有-->"+a+"岁了");
            System.out.println("喜羊羊大概有-->"+b+"岁了");
            System.out.println("他的名字是-->"+name);
        };
        love.love(234,63,"智羊羊");
    }
}

interface ILove{
    void love(int a,int b,String name);
}

3、线程状态

如下图所示:

在这里插入图片描述

线程停止:
//测试线程停止
//线程最好正常停止--->利用次数,不建议死循环
//建议使用标志位--->设置一个标识位
//不要使用stop或者destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{


    //设置一个标志位
    private boolean flag=true;

    @Override
    public void run() {
        int i=0;
        while (flag){
            System.out.println("线程开始运行----->"+(i++));
        }
    }
//设置一个公开的方法停止线程,转换标志位
    public void stop(){
        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.stop();//调用stop方法转换标志位,停止线程!
                System.out.println("线程停止!!!");
            }
        }
    }
}

线程休眠:
  • sleep(时间)指定当前线程阻塞的毫秒数;
  • sleep存在异常InterruptedException;
  • sleep时间达到后,线程进入就绪状态;
  • sleep可以模拟网络延时,倒计时等。
  • 每一个对象都有一个锁,sleep不会释放锁。
//模拟网络延时:放大问题的发生性
public class TestSleep implements Runnable{
    private int ticketNum=10;

    @Override
    public void run() {
        while (true){
            if (ticketNum<=0){
                break;
            }
            //模拟延时
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNum--+"张票");
        }
    }

    public static void main(String[] args) {
        TestSleep runnableDemo02 = new TestSleep();

        new Thread(runnableDemo02,"小李子").start();
        new Thread(runnableDemo02,"小郭子").start();
        new Thread(runnableDemo02,"盗版").start();
    }

}

//实例模拟计时器
import java.text.SimpleDateFormat;
import java.util.Date;


public class TestSleep2 {


    public static void main(String[] args) {

        //打印当前时间
        Date startTime=new Date(System.currentTimeMillis());//获得系统当前时间
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(startTime));
                startTime=new Date(System.currentTimeMillis());//更新系统当前时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }



    }
    模拟倒计时
//        try {
//            timeDown();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }

//    public static void timeDown() throws InterruptedException {
//        int num=10;
//        while (true){
//            Thread.sleep(1000);
//            System.out.println("倒计时-->"+(num--));
//            if (num<=0){
//                break;
//            }
//        }
//    }
}
线程礼让:
//礼让线程  不一定成功 看CPU心情
public class TestYield {

    public static void main(String[] args) {

        MyYield myYield = new MyYield();

        new Thread(myYield,"A").start();
        new Thread(myYield,"B").start();
    }

}

class MyYield implements Runnable{

    @Override
    public void run() {

        System.out.println(Thread.currentThread().getName()+"线程开始执行!");
        Thread.yield();//礼让
        System.out.println(Thread.currentThread().getName()+"线程停止执行!");
    }
}
线程强制执行:
//线程强制执行
public class TestJoin implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 500; i++) {
            System.out.println("VIP线程先走!"+i);
        }

    }


    public static void main(String[] args) throws InterruptedException {
        //开启线程
        TestJoin testJoin=new TestJoin();
        Thread thread=new Thread(testJoin);


        //主线程
        for (int i = 0; i < 100; i++) {
            if (i==50){
                thread.start();
                thread.join();//强制执行
            }
            System.out.println("main"+i);
        }
    }
}
线程状态:
//观察线程状态
public class TestState {

    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 2; 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);//RUNNABLE

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

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

        MyPriority myPriority = new MyPriority();

        Thread t1=new Thread(myPriority);
        Thread t2=new Thread(myPriority);
        Thread t3=new Thread(myPriority);
        Thread t4=new Thread(myPriority);
        Thread t5=new Thread(myPriority);
        Thread t6=new Thread(myPriority);


        //运行:先设置优先级,然后在启动
        t1.start();

        t2.setPriority(Thread.MIN_PRIORITY);//1
        t2.start();

        t3.setPriority(8);
        t3.start();

        t4.setPriority(Thread.MAX_PRIORITY);//10
        t4.start();

        t5.setPriority(4);
        t5.start();

        t6.setPriority(6);
        t6.start();
    }

}

class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"----->"+Thread.currentThread().getPriority());
    }
}
守护线程:
//测试守护线程
public class TestDaemon {

    public static void main(String[] args) {
        God god = new God();
        You you = new You();

        Thread thread=new Thread(god);
        thread.setDaemon(true);//默认值是false 表示用户线程  正常的线程都是用户线程

        thread.start();//上帝 守护线程

        new Thread(you).start();//You 用户线程启动
    }
}

//上帝
class God implements Runnable{
    //守护线程
    @Override
    public void run() {
          while (true){
              System.out.println("上帝一直都存在。");
          }
    }
}



//你
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("你一直在活着。");
        }
        System.out.println("=========goodbye! world!=========");
    }
}

4、线程同步机制(synchronized–隐式锁)

  • 并发:同一个对象被多个线程同时操作

同步方法和同步块:

public class UnSafeBank {
    public static void main(String[] args) {
        Account account = new Account(1000,"结婚基金");

        Drawing youSister = new Drawing(account,50,"你姐姐");//你姐姐的
        Drawing you = new Drawing(account,100,"you");//你的

        youSister.start();
        you.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;
    }

    @Override
    public void run() {
//锁的对象是变化的量----增删改
        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;
            System.out.println(account.name + "余额是:" + account.money);
            //Thread.currentThread().getName()==>this.getName()
            System.out.println(this.getName()+ "手里的钱是:" +nowMoney);

        }

    }
}

JUC测试:

import java.util.concurrent.CopyOnWriteArrayList;

//测试juc安全类型的集合    CopyOnWriteArrayList 安全的
public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();

        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                    list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

5、死锁

产生死锁的必要条件:
  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间行成一种头尾相接的循环等待资源关系。
import java.util.concurrent.locks.ReentrantLock;

//测试Lock锁
public class TestLock {
    public static void main(String[] args) {
        MyLock myLock = new MyLock();

        new Thread(myLock).start();
        new Thread(myLock).start();
        new Thread(myLock).start();

    }

}


class MyLock implements Runnable{

    //火车票
    int ticketNum=10;
    //定义lock锁
    private final ReentrantLock reentrantLock=new ReentrantLock();

    @Override
    public void run() {
        while (true){
            //加锁
            try {
                reentrantLock.lock();
                if (ticketNum>0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(ticketNum--);
                }else {
                    break;
                }
            } finally {
                //解锁
                reentrantLock.unlock();
            }

        }

    }
}

6、线程协作

生产者消费者问题:
//生产者消费者问题----通过设置缓冲区解决(管程法)
public class TestPC {
    public static void main(String[] args) {

        SynContainer synContainer = new SynContainer();

        Producer producer = new Producer(synContainer);
        Consumer consumer = new Consumer(synContainer);

        producer.start();
        consumer.start();
    }

}
//生产者
class Producer extends Thread{
    SynContainer container;

    public Producer(SynContainer container) {
        this.container = container;
    }
    //生产产品

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            container.push(new Product(i));
            System.out.println("生产了---->"+i+"个产品。");
        }
    }
}

//消费者
class Consumer extends Thread{
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }
    //消费产品
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了"+container.pop().id+"个产品*******");
        }
    }
}

//产品
class Product{
  int id;//产品编号

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

//缓冲区  SynContainer
class SynContainer{
    //设置产品的容器大小
    Product[] products=new Product[10];
    //设置计数器
    int count=0;

    //生产者生产产品
    public synchronized void push(Product product){
        //判断容器是否满了,如果满了,就需要等待消费者消费
        if (count==products.length){
            try {
                this.wait();  //生产等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果容器不满,就需要生产者生产产品
        products[count]=product;
        count++;

        //可以通知消费者消费了
        this.notifyAll();

    }


    //消费者消费产品
    public synchronized Product pop(){
        //判断是否可以消费产品
        if (count==0){
            //消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Product product=products[count];

        //可以通知生产者进行生产了
        this.notifyAll();
        return product;
    }

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值