线程生产者与消费者——盒子中存取苹果

线程知识:

synchronized

synchronized 用在方法签名上(以test为例),当某个线程调用此方法时,会获取该实例的对象锁,方法未结束之前,其他线程只能去等待。当这个方法执行完时,才会释放对象锁。其他线程才有机会去抢占这把锁,去执行方法test,但是发生这一切的基础应当是所有线程使用的同一个对象实例,才能实现互斥的现象。否则synchronized关键字将失去意义。
使用synchronized代码块,可以只对需要同步的代码进行同步,这样可以大大的提高效率。

synchronized(obj){
//todo code here
}

wait()

释放占有的对象锁,线程进入等待池,释放cpu,而其他正在等待的线程即可抢占此锁,获得锁的线程即可运行程序。

sleep()

线程调用此方法后,会休眠一段时间,休眠期间,会暂时释放cpu,但并不释放对象锁。也就是说,在休眠期间,其他线程依然无法进入此代码内部。休眠结束,线程重新获得cpu,执行代码。

notify()

该方法会唤醒因为调用对象的wait()而等待的线程,其实就是对对象锁的唤醒,从而使得wait()的线程可以有机会获取对象锁。调用notify()后,并不会立即释放锁,而是继续执行当前代码,直到synchronized中的代码全部执行完毕,才会释放对象锁。

notifyAll()

唤醒所有等待的线程。
wait() 与notify()/notifyAll()都是Object的方法,并不是线程的方法!

关键问题

Runnable定义的子类中没有start()方法,只有Thread类中才有。
在程序开发中只要是多线程肯定永远以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:
避免点继承的局限,一个类可以继承多个接口。

先明白两个概念:锁池和等待池。synchronized是锁池,wait、notify、notifyAll是等待池。等待池的对象是不会竞争锁的,当notifyAll后,等待池中的线程会被唤醒进入到该线程的锁池中重新竞争对象锁,重新获得锁后的对象会从wait后继续执行代码,其他对象会被阻塞,而不是wait。被阻塞的对象会等待下一次被唤醒(notify、notifyAll)。另外,notify不是线程安全的,notifyAll才是。

适合于资源的共享

题目

生产者:向盒子里放苹果
消费者:从盒子里取苹果
盒子:苹果数量不超过5

这个问题用线程来实现

先建立一个苹果类
给生成的苹果一个编号

public class Apple {
    //苹果编号
    int id;

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

盒子

public class Box {
    //装苹果的盒子 为什么是链表 因为 它有boxs.removeFirst();方法 方便取出苹果
    public LinkedList<Apple> boxs =new LinkedList<Apple>();

    public List<Apple> getBoxs() {
        return boxs;
    }

    public void setBoxs(LinkedList<Apple> boxs) {
        this.boxs = boxs;
    }

    public synchronized void push(Apple apple,String threadName){
        //盒子容量5
        while (boxs.size()==5){
           try {
                System.out.println(threadName+":盒子满了,放不下(进入等待状态),快叫消费者来消费");
                this.wait();
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
        }
        //唤醒所有等待线程 notifyAll();安全  ---notify()不安全
        this.notifyAll();
        //苹果放进盒子中
        System.out.println(threadName+"生产苹果"+apple.id);
        boxs.add(apple);

        try {
            //线程等待0.5秒便于观察
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void  pop(String threadName){
        while (boxs.size()==0){
            try {
                System.out.println(threadName+":盒子没苹果了(进入等待状态),快叫生产者来生产");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //唤醒所有等待线程 notifyAll();安全  ---notify()不安全
        this.notifyAll();
        //盒子中拿去第一个苹果
        System.out.println(threadName+"消费苹果");
        boxs.removeFirst();

        try {
            //线程等待0.5秒便于观察
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

消费者

public class Consumer implements Runnable {
    Box box=null;

    public Consumer(Box box) {
        this.box = box;
    }

    @Override
    public void run() {
        while (true) {
        	//互斥
            synchronized (Consumer.class) {


                box.pop(Thread.currentThread().getName());
            }


        }
    }
}

生产者

public class Producer  implements  Runnable{
	
    public static Integer count = 0;

    Box box = null;

    public Producer(Box box) {
        this.box = box;
    }

    public void run() {
        while (true) {
            synchronized (Producer.class) {
                count++;
                //生产者给苹果编号
                Apple apple =new Apple(count);

                box.push(apple,Thread.currentThread().getName());
            }


        }
    }


}

测试类

public class AppleThreadTest {
    public static void main(String[] args) {
        //盒子
        Box box =new Box();

        //生产者
        Producer p1=new Producer(box);
        Producer p2=new Producer(box);

        //消费者
        Consumer c1 =new Consumer(box);
        Consumer c2 =new Consumer(box);
        //创建线程
        Thread t1=new Thread(p1,"生产者——小刘");
        Thread t2=new Thread(p2,"生产者——小李");
        Thread t3=new Thread(c1,"消费者——老刘");
        Thread t4=new Thread(c2,"消费者——老李");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

运行结果:
在这里插入图片描述
我们发现都是盒子里没苹果了,为什么呢?
因为一共4个线程2个生产者2个消费者,优先级都一样 加减基本维持在0
我们可以改变其中一个的优先级
c2.setPriority(10);
java 中的线程优先级的范围是1~10,默认的优先级是5。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值