day_20~21:多线程
一、什么是进程?
进程是系统进行资源分配和调度的独立单元,每一个进程都有它的“独立”内存空间和系统资源。
二、单进程操作系统和多进程操作系统的区别
单进程操作系统(DOS):一次只能执行一个进程
单用户多进程操作系统(Windows):一次可以执行多个进程
多用户多进程操作系统(Linux、Unix):一次可以执行多个进程
三、现在的多核CPU是否可以让系统在同一时刻可以执行多个任务呢?
理论上是绝对可以的,实际上发生这种情况较少。
四、什么是线程,理解线程和进程的关系
线程是进程里面的一条执行路径,每个线程共享进程里面的内存空间和系统资源
五、我们应用的软件有哪些是多线程的应用?
基本上都是多线程(因为现在用户体验要求越来越高)
六、Java中,如何来编写一个多线程的应用?
1、线程类:创建一个类,继承Thread,重写run方法 ------ new MyThread().start()
2、任务类:创建一个类,实现Runnable接口里面的run方法 ------ new Thread(new Task())
3、带有返回值的任务类。
主线路从上往下,多线程多条执行路线(随机)
public class MyThread extends Thread{ @Override public void run() {//编写当前线程的功能 System.out.println("创建线程类多线程"); } } public class Test01 { public static void main(String[] args) { //创建线程类的对象 MyThread thread = new MyThread(); //启动线程:thread线程抢到资源后才能运行run方法 thread.start(); } }
//任务类 public class Task implements Runnable{ @Override public void run() { System.out.println("任务类多线程"); } } public class Test02 { public static void main(String[] args) { //创建线程对象,并把任务交给他 Thread thread = new Thread(new Task()); //启动线程 thread.start(); } }
public class PTest01 { public static void main(String[] args) { //创建并启动子线程 new MyThread1().start(); for (int i = 1; i <= 200; i++) { System.out.println(i); } } } class MyThread1 extends Thread { @Override public void run() { for (int i = 1; i <= 200; i++) { System.out.println(i); } } }
经典面试题:请问当我们编写一个单纯的main方法时,此时该程序是否为单线程的?为什么?
是多线程程序,因为后台有一个守护线程叫做垃圾回收器(线程)。在后台默默守护着非守护线程,等到非守护线程全部消亡时,守护线程会自动消亡
七、线程的优先级
优先级别从大到小:10 --1
设置优先级别会让概率变大一些
public class Test01 { public static void main(String[] args) { /** * 练习:在主线程中创建两个以上的子线程,并且设置不同优先级,观察其优先级对线程执行结果的”影响”。 */ A a = new A(); B b = new B(); C c = new C(); //设置优先级别 a.setPriority(Thread.MAX_PRIORITY); b.setPriority(Thread.NORM_PRIORITY); c.setPriority(Thread.MIN_PRIORITY); a.start(); b.start(); c.start(); } } class A extends Thread{ @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("a:" + i); } } } class B extends Thread{ @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("b:" + i); } } } class C extends Thread{ @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("c:" + i); } } }
八、给线程自定义名称
public class Test02 { public static void main(String[] args) { // MyThread thread = new MyThread("线程1"); // MyThread thread2 = new MyThread("线程2"); MyThread thread = new MyThread(); MyThread thread2 = new MyThread(); thread.setThreadName("线程1"); thread2.setThreadName("线程2"); thread.start(); thread2.start(); } } class MyThread extends Thread { private String threadName; public MyThread() { } public MyThread(String threadName) { this.threadName = threadName; } public String getThreadName() { return threadName; } public void setThreadName(String threadName) { this.threadName = threadName; } @Override public void run() { for (int i = 1; i < 100; i++) { System.out.println(threadName + " -- " + i); } } }
public class Test01 { public static void main(String[] args) { /** * 给线程自定义名称 */ MyThread t1 = new MyThread("线程1"); MyThread t2 = new MyThread("线程2"); //调用父类设置名字的方法 // t1.setName("线程1"); // t2.setName("线程2"); t1.start(); t2.start(); } } class MyThread extends Thread{ public MyThread() { } public MyThread(String threaName) { super(threaName);//把名字传给父类了 } @Override public void run() { for (int i = 1; i <= 100; i++) { // Thread thread = Thread.currentThread();//获取当先线程的对象 // String name = thread.getName();//获得当前线程对象的名字 System.out.println(Thread.currentThread().getName() + " -- " + i); } } }
九、让线程休眠
public class Test { public static void main(String[] args) throws InterruptedException { /** * 练习:编写一个抽取学员回答问题的程序,要求倒数三秒后输出被抽中的学员姓名 */ String[] names = new String[] { "赤名莉香", "关口里美", "长崎尚子", "周芷若", "郑强", "和贺夏树" }; Random ran = new Random(); for (int i = 3; i > 0; i--) { System.out.println(i); Thread.sleep(1000); } System.out.println(names[ran.nextInt(names.length)]); } }
Thread.sleep()是静态,当前方法写在哪个线程里,哪个线程就休眠
十、线程的礼让
public class Test01 { public static void main(String[] args) { A a = new A(); B b = new B(); a.start(); b.start(); } } class A extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("A" + i); Thread.yield(); } } } class B extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("B" + i); } } }
yeild()礼让:是静态,当前方法写在哪个线程里,哪个线程就礼让,礼让是退出资源,然后再次进入到抢资源的状态
十一、线程的合并
主线程和子线程同时运行,满足一定条件后,让子线程先运行至结束
public class Test01 { public static void main(String[] args) throws InterruptedException { /** * 练习:主线程和子线程各打印200次,从1开始每次增加1,当主线程打印到10之后, * 让子线程先打印完再打印主线程 */ MyTread t1 = new MyTread(); t1.start(); for (int i = 1; i <= 200; i++) { System.out.println("主线程:" + i); if(i == 10){ //把子线程合并 t1.join(); } } } } class MyTread extends Thread{ @Override public void run() { for (int i = 1; i <= 200; i++) { System.out.println("子线程:" + i); } } }
public class Test02 { public static void main(String[] args) { /** * A线程和B线程各打印200次,从1开始每次增加1,当A线程打印到10之后, 让B线程先打印完再打印A线程 */ B b = new B(); A a = new A(b); a.start(); b.start(); } } class A extends Thread { private B b; public A(B b) { this.b = b; } @Override public void run() { for (int i = 1; i <= 200; i++) { if (i == 10) { try { b.join(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("A" + i); } } } class B extends Thread { @Override public void run() { for (int i = 1; i <= 200; i++) { System.out.println("B" + i); } } }
join()合并:写在哪个线程里,就合并到哪个线程
十二、线程的中断
public class Test01 { public static void main(String[] args) throws Exception { MyThread thread = new MyThread(); thread.start(); Thread.sleep(3000); thread.setFlag(false); } } class MyThread extends Thread { private boolean flag = true; public void setFlag(boolean flag) { this.flag = flag; } @Override public void run() { while (flag) { System.out.println("怒发冲冠凭阑处。。。"); } } }
public class Test02 { public static void main(String[] args) throws Exception { MyThread1 myThread1 = new MyThread1(); myThread1.start(); Thread.sleep(3000); //改变线程状态 myThread1.interrupt(); } } class MyThread1 extends Thread { @Override public void run() { // 判断当前线程是否已中断 while (!Thread.currentThread().isInterrupted()) { System.out.println("壮志饥餐胡虏肉。。。"); } } }
十三、线程局部变量(实现线程范围内的共享变量)
public class Test01 { public static ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); public static void main(String[] args) { //线程1 new Thread(new Runnable() { @Override public void run() { int i = 10; Test01.map.put(Thread.currentThread().getName(), i);//存入数据 new A().print();//Thread-0 -- A类 -- 10 new B().print();//Thread-0 -- B类 -- 10 } }).start(); //线程2 new Thread(new Runnable() { @Override public void run() { int i = 20; Test01.map.put(Thread.currentThread().getName(), i);//存入数据 new A().print();//Thread-1 -- A类 -- 20 new B().print();//Thread-1 -- B类 -- 20 } }).start(); } } class A{ public void print(){ String name = Thread.currentThread().getName(); Integer value = Test01.map.get(name); System.out.println(name + " -- A类 -- " + value); } } class B{ public void print(){ String name = Thread.currentThread().getName(); Integer value = Test01.map.get(name); System.out.println(name + " -- B类 -- " + value); } }
public class Data { private String name; private int age; public Data() { } public Data(String name, int age) { super(); this.name = name; this.age = age; } @Override public String toString() { return "Data [name=" + name + ", age=" + age + "]"; } } public class Test002 { public static ConcurrentHashMap<String, Data> map = new ConcurrentHashMap<>(); public static void main(String[] args) { // 线程1 new Thread(new Runnable() { @Override public void run() { Test002.map.put(Thread.currentThread().getName(), new Data("赤名莉香", 18)); new C().print();// Thread-0 -- A类 -- Data [name=赤名莉香, age=18] new D().print();// Thread-0 -- B类 -- Data [name=赤名莉香, age=18] } }).start(); new Thread(new Runnable() { @Override public void run() { Test002.map.put(Thread.currentThread().getName(), new Data("郑强", 1314)); new C().print();// Thread-1 -- A类 -- Data [name=郑强, age=1314] new D().print();// Thread-1 -- B类 -- Data [name=郑强, age=1314] } }).start(); } } class C { public void print() { String name = Thread.currentThread().getName(); Data value = Test002.map.get(name); System.out.println(name + " -- A类 -- " + value); } } class D { public void print() { String name = Thread.currentThread().getName(); Data value = Test002.map.get(name); System.out.println(name + " -- B类 -- " + value); } }
public class Data2 { private String name; private int age; public Data2() { } public Data2(String name, int age) { super(); this.name = name; this.age = age; } public Data2 getInstance(String name, int age) { Data2 data = Test0003.local.get(); if (data == null) { data = new Data2(name, age); } else { data.setName(name); data.setAge(age); } return data; } @Override public String toString() { return "Data [name=" + name + ", age=" + age + "]"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } public class Test0003 { public static ThreadLocal<Data2> local = new ThreadLocal<>(); public static void main(String[] args) { // 线程1 new Thread(new Runnable() { @Override public void run() { Test0003.local.set(new Data2("赤名莉香", 18)); new E().print();// Thread-0 -- A类 -- Data [name=赤名莉香, age=18] new F().print();// Thread-0 -- B类 -- Data [name=赤名莉香, age=18] } }).start(); new Thread(new Runnable() { @Override public void run() { Test0003.local.set(new Data2("郑强", 1314)); new E().print();// Thread-1 -- A类 -- Data [name=郑强, age=1314] new F().print();// Thread-1 -- B类 -- Data [name=郑强, age=1314] } }).start(); } } class E { public void print() { String name = Thread.currentThread().getName(); Data2 value = Test0003.local.get(); System.out.println(name + " -- A类 -- " + value); } } class F { public void print() { String name = Thread.currentThread().getName(); Data2 value = Test0003.local.get(); System.out.println(name + " -- B类 -- " + value); } }
A) 实现单个数据共享
B) 实现多个数据共享--打包成实体类
C) 类似于单例模式的数据共享
十四、线程的生命周期

注意:
进程与进程:独享内存空间和系统资源
同一个进程里的多个线程:共享聂村空间和系统资源
一个进程里可以有多个线程:多个线程不同的执行路径(不同的功能)
一个进程里只能有一个主线程
十五、作业
1、计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
public class test01 { public static void main(String[] args) throws Exception { /** * 计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。 */ int[] nums = new int[20000]; for (int i = 0; i < nums.length; i++) { nums[i] = i; } MyThread t1 = new MyThread(nums, 0, 5000); MyThread t2 = new MyThread(nums, 5000, 10000); MyThread t3 = new MyThread(nums, 10000, 15000); MyThread t4 = new MyThread(nums, 15000, 20000); t1.start(); t2.start(); t3.start(); t4.start(); t1.join(); t2.join(); t3.join(); t4.join(); System.out.println(t1.getNum() + t2.getNum() + t3.getNum() + t4.getNum()); } } class MyThread extends Thread { private int[] nums; private int startIndex; private int endIndex; private int num; public MyThread(int[] nums, int startIndex, int endIndex) { this.nums = nums; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { for (int i = startIndex; i < endIndex; i++) { num += nums[i]; } } public int getNum() { return num; } }
2、采用多线程技术,改造之前的断点续传的案例,实现多线程断点续传,要求线程的数量可由客户端程序来设置,实现思路如下:根据线程的数量,将文件分成多段,每个线程负责其中一段的拷贝工作
public class Test02 { public static void main(String[] args) { /** * 采用多线程技术,改造之前的断点续传的案例,实现多线程断点续传, 要求线程的数量可由客户端程序来设置,实现思路如下: * 根据线程的数量,将文件分成多段,每个线程负责其中一段的拷贝工作 */ System.out.println("请输入想分几段来完成拷贝:"); Scanner scan = new Scanner(System.in); int lenNum = scan.nextInt(); File file = new File("上原亚衣.avi"); long fileLen = file.length(); long foreLen = fileLen / lenNum; long lastName = fileLen / lenNum + fileLen % lenNum; for (int i = 0; i < lenNum - 1; i++) { new YouThread(file, foreLen, foreLen * i).start(); } new YouThread(file, lastName, foreLen * (lenNum - 1)).start(); scan.close(); } } class YouThread extends Thread { private File file; private long length; private long startIndex; public YouThread(File file, long length, long startIndex) { this.file = file; this.length = length; this.startIndex = startIndex; } @Override public void run() { RandomAccessFile r = null; RandomAccessFile w = null; try { r = new RandomAccessFile(file, "r"); w = new RandomAccessFile("copy.avi", "rw"); r.seek(startIndex); w.seek(startIndex); byte[] bys = new byte[1024]; int len; long num = 0; while ((len = r.read(bys)) != -1) { w.write(bys, 0, len); num += len; if (num >= length) { break; } } } catch (Exception e) { } finally { try { r.close(); } catch (IOException e1) { e1.printStackTrace(); } try { w.close(); } catch (IOException e) { e.printStackTrace(); } } } }
3、铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售
public class Test01 { public static void main(String[] args) { /** * 需求:铁道部发布了一个售票任务,要求销售1000张票,要求有3个窗口来进行销售, 请编写多线程程序来模拟这个效果 * * 问题一:三个线程各卖了1000张票 解决:三个线程共用同一个任务类的对象,并且把ticket变成全局变量 * * 问题二:有一些票卖重了 解决:卖票的打印语句必须和票的自减一起运行完毕,才能退出系统资源 * * 问题三:卖负票 解决:在锁里再加个判断 * * synchronized --- 互斥锁、同步锁: 锁对象:多个线程之间必须共用同一把锁对象,才能互相排斥 * * 同步代码块: synchronized(锁对象){ ......... } * * 同步方法: public synchronized void method02(){} * * 锁对象为:this * * Lock锁: 锁对象就是本身 * * synchronized vs Lock 答:Lock锁可以实现synchronized锁的所有功能,但是Lock锁必须手动解锁 */ Task task = new Task(); Thread t1 = new Thread(task, "窗口1"); Thread t2 = new Thread(task, "窗口2"); Thread t3 = new Thread(task, "窗口3"); t1.start(); t2.start(); t3.start(); } } class Task implements Runnable { int ticket = 1000;// 票 Lock lock = new ReentrantLock(); @Override public void run() { // while (ticket > 0) { // method02(); // } method03(); } private void method03() { while (ticket > 0) { lock.lock(); if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票"); ticket--; if (ticket == 0) { System.out.println(Thread.currentThread().getName() + "销售完了"); } } else { System.out.println(Thread.currentThread().getName() + "销售完了"); } lock.unlock(); } } // 同步方法:锁对象--this private synchronized void method02() { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票"); ticket--; if (ticket == 0) { System.out.println(Thread.currentThread().getName() + "票已经售完"); } } else { System.out.println(Thread.currentThread().getName() + "票已经售完"); } } // 同步代码块实现 private void nethod01() { while (ticket > 0) { synchronized (this) { method02(); } } } }
public class Test02 { public static void main(String[] args) { new MyThread("窗口1").start(); new MyThread("窗口2").start(); new MyThread("窗口3").start(); } } class MyThread extends Thread { static int ticket = 1000; static Object obj = new Object(); static Lock lock = new ReentrantLock(); public MyThread(String name) { super(name); } @Override public void run() { // while (ticket > 0) { // method02(); // } while (ticket > 0) { lock.lock(); if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票"); ticket--; if (ticket == 0) { System.out.println(Thread.currentThread().getName() + "已经售完"); } } else { System.out.println(Thread.currentThread().getName() + "已经售完"); } lock.unlock(); } } private static synchronized void method02() { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票"); ticket--; if (ticket == 0) { System.out.println(Thread.currentThread().getName() + "已经售完"); } } else { System.out.println(Thread.currentThread().getName() + "已经售完"); } } private void method01() { while (ticket > 0) { // synchronized ("123") { // synchronized (obj) { synchronized (String.class) { if (ticket > 0) { System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket + "张票"); ticket--; if (ticket == 0) { System.out.println(Thread.currentThread().getName() + "已经售完"); } } else { System.out.println(Thread.currentThread().getName() + "已经售完"); } } } } }
十六、多线程下的单例模式
/** * 多线程下的单例模式 * 优点:效率高、不浪费资源、线程安全 */ public class MyClass { private static MyClass my = null; private MyClass() { } public static MyClass getInstance(){ if(my != null){ return my; } synchronized ("123") { if(my == null){ my = new MyClass(); } } return my; } public static void print(){ System.out.println("夏凡你是最胖的..."); } }
十七、死锁
public class Test01 { public static void main(String[] args) { //死锁案例: //1.编写多线程时,一定要多分析 //2.锁里再放锁,容易造成死锁 new MyThread(true).start(); new MyThread(false).start(); } } class MyThread extends Thread{ boolean flag; public MyThread(boolean flag) { this.flag = flag; } @Override public void run() { if(flag){ synchronized (KuaiZi.a) { try { Thread.sleep(1000); } catch (InterruptedException e) { } synchronized (KuaiZi.b) { System.out.println("哲学家1 --- 吃饭了"); } } }else{ synchronized (KuaiZi.b) { try { Thread.sleep(1000); } catch (InterruptedException e) { } synchronized (KuaiZi.a) { System.out.println("哲学家2 --- 吃饭了"); } } } } } class KuaiZi{ public static Object a = new Object(); public static Object b = new Object(); }
如果出现同步嵌套(同步里面包含同步),就有可能会产生死锁问题
只有对方都拥有了彼此的资源且不愿意释放时,才会出现死锁问题
十八、线程池
//线程池底层实现 public class ThreadPool { private ArrayList<MyThread> list = new ArrayList<>(); private int index = 0; public ThreadPool(int threadNum) { for (int i = 0; i < threadNum; i++) { MyThread thread = new MyThread("pool - thread -" + i); list.add(thread); } } private class MyThread extends Thread { public MyThread(String name) { super(name); } } }
public class Test01 { public static void main(String[] args) { // 创建只有一个线程的线程池 ExecutorService pool = Executors.newSingleThreadExecutor(); // 创建指定线程个数的线程池 ExecutorService pool1 = Executors.newFixedThreadPool(2); // 创建带有缓冲的线程池 ExecutorService pool2 = Executors.newCachedThreadPool(); // 提交任务 pool2.submit(new Task()); pool2.submit(new Task()); pool2.submit(new Task()); pool2.submit(new Task()); // 关闭线程池 pool.shutdown(); } } class Task implements Runnable { @Override public void run() { for (int i = 0; i < 4; i++) { System.out.println(Thread.currentThread().getName() + "-----" + i); } } }
带有返回值的任务类 + 线程池的使用
需求:计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。
public class Test01 { public static void main(String[] args) throws InterruptedException, ExecutionException { /** * 需求:计算任务,一个包含了2万个整数的数组,分拆了多个线程来进行并行计算,最后汇总出计算的结果。 */ int[] is = new int[20000]; for (int i = 0; i < is.length; i++) { is[i] = (i+1); } ExecutorService pool = Executors.newFixedThreadPool(4); //提交带有返回值的任务类,执行完毕后会把任务类的返回值放在Futuer对象中 //注意submit是线程阻塞的方法 Future<Integer> s1 = pool.submit(new Task(is, 0, 5000)); Future<Integer> s2 = pool.submit(new Task(is, 5000, 10000)); Future<Integer> s3 = pool.submit(new Task(is, 10000, 15000)); Future<Integer> s4 = pool.submit(new Task(is, 15000, 20000)); //获取对象中的数据并求和 System.out.println(s1.get() + s2.get() + s3.get() + s4.get()); pool.shutdown(); } } class Task implements Callable<Integer>{ private int[] is; private int startIndex; private int endIndex; public Task(int[] is, int startIndex, int endIndex) { this.is = is; this.startIndex = startIndex; this.endIndex = endIndex; } //类似于Runnable接口里的run方法 @Override public Integer call() throws Exception { int sum = 0; for (int i = startIndex; i < endIndex; i++) { sum += is[i]; } return sum; } }
十九、生产者消费者模型
与之前多线程卖票的区别:

案例:(生产手机、消费手机)
public class Phone { private String name; private double price; private boolean store; public Phone() { } public Phone(String name, double price, boolean store) { this.name = name; this.price = price; this.store = store; } public String getName() { return name; } public void setName(String name) { this.name = name; } 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 [name=" + name + ", price=" + price + ", store=" + store + "]"; } }
public class Producer extends Thread { private Phone phone; private static boolean bool = true;// 如果是多个对象的话应该放在这里并用static修饰 public Producer(Phone phone) { this.phone = phone; } @Override public void run() { while (true) { synchronized (phone) { while (phone.isStore()) {// 如果是单个生产者对象的话,用if try { phone.wait(); } catch (InterruptedException e) { } } if (bool) { phone.setName("赤名莉香"); phone.setPrice(1314); } else { phone.setName("郑强"); phone.setPrice(520); } bool = !bool; phone.setStore(true); // 唤醒 phone.notifyAll();// 如果是单个生产者对象的话,唤醒就用phone.notify() } } } } public class Consumer extends Thread { private Phone phone; public Consumer(Phone phone) { this.phone = phone; } @Override public void run() { while (true) { synchronized (phone) { while (!phone.isStore()) { try { phone.wait(); } catch (InterruptedException e) { } } System.out.println(phone.getName() + " *** " + phone.getPrice()); phone.setStore(false); phone.notifyAll(); } } } }
public class Test01 { public static void main(String[] args) { Phone phone = new Phone(); Producer p1 = new Producer(phone); Producer p2 = new Producer(phone); Consumer c1 = new Consumer(phone); Consumer c2 = new Consumer(phone); p1.start(); p2.start(); c1.start(); c2.start(); } }
仓储模型
//仓库 public class Store { private int max = 20;// 仓库最大容量 private int num = 0;// 仓库现在库存量 // 入库 public void push() { synchronized (this) { if (num >= max) { try { this.wait(); } catch (InterruptedException e) { } } num++; System.out.println("入库,库存量:" + num); this.notify(); } } // 出库 public void pop() { synchronized (this) { if (num <= 0) { try { this.wait(); } catch (InterruptedException e) { } } num--; System.out.println("出库,库存量:" + num); this.notify(); } } }
public class Producer extends Thread { private Store store; public Producer(Store store) { this.store = store; } @Override public void run() { while (true) { store.push(); } } } public class Consumer extends Thread { private Store store; public Consumer(Store store) { this.store = store; } @Override public void run() { while (true) { store.pop(); } } }
public class Test { public static void main(String[] args) { Store store = new Store(); Producer p = new Producer(store); Consumer c = new Consumer(store); p.start(); c.start(); } }
当有多个生产者和消费者时改动跟上面一样改。( if 改为 while、this.notify 改为 this.notifyAll )
十九、作业
public class Cake implements Serializable { /** * */ private static final long serialVersionUID = 7087277041944375330L; private String name; private String date; public Cake() { } public Cake(String name, String date) { this.name = name; this.date = date; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } @Override public String toString() { return "Cake [name=" + name + ", date=" + date + "]"; } }
public class Producer extends Thread { private Store store; public Producer(Store store,String name) { super(name); this.store = store; } @Override public void run() { while (true) { store.push(); try { sleep(2000); } catch (InterruptedException e) { } } } } public class Consumer extends Thread { private Store store; public Consumer(Store store,String name) { super(name); this.store = store; } @Override public void run() { while (true) { store.pop(); try { sleep(2000); } catch (InterruptedException e) { } } } }
//仓库 public class Store { private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public LinkedList<Cake> cakes = new LinkedList<>(); private int num = 0; private int max = 20; private String name; private String date; public void push() { synchronized (this) { while (cakes.size() == max) { try { this.wait(); } catch (InterruptedException e) { } } num++; name = "cake" + String.valueOf(num); date = sdf.format(new Date()); Cake cake = new Cake(name, date); cakes.add(cake); System.out.println(Thread.currentThread().getName() + " -- " + "制作蛋糕:" + cake); this.notifyAll(); } } public void pop() { synchronized (this) { while (cakes.size() == 0) { try { this.wait(); } catch (InterruptedException e) { } } // try { // Thread.sleep(2000); // } catch (InterruptedException e) { // } num--; // Cake removeFirst = cakes.removeFirst(); System.out.println(Thread.currentThread().getName() + " -- " + "购买蛋糕:" + cakes.removeFirst()); this.notifyAll(); } } }
public class Test { public static void main(String[] args) { /** * 有一个蛋糕店,最大库存数可以存储20个蛋糕,有5个生产师傅不断生产,有5个顾客不断的买, * 生产一个蛋糕需要2秒,卖出的蛋糕必须按照时间顺序,卖最早生产的蛋糕 */ Store store = new Store(); Producer p1 = new Producer(store,"生产者1"); Producer p2 = new Producer(store,"生产者2"); Producer p3 = new Producer(store,"生产者3"); Producer p4 = new Producer(store,"生产者4"); Producer p5 = new Producer(store,"生产者5"); Consumer c1 = new Consumer(store,"消费者1"); Consumer c2 = new Consumer(store,"消费者2"); Consumer c3 = new Consumer(store,"消费者3"); Consumer c4 = new Consumer(store,"消费者4"); Consumer c5 = new Consumer(store,"消费者5"); p1.start(); p2.start(); p3.start(); p4.start(); p5.start(); c1.start(); c2.start(); c3.start(); c4.start(); c5.start(); } }

浙公网安备 33010602011771号