`
FindWG
  • 浏览: 8026 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

马士兵线程 消费者和生产者部分的错误

阅读更多

现在在学java基础,在看一些马士兵老师的视频,确实通俗易懂。

最近看到线程这一章时,发现运行 消费者和生产者 代码部分时,总会出现先消费生产。

源代码如下:

public class ProducerConsumer {
	public static void main(String[] args) {
		SyncStack ss = new SyncStack();
		Producer p = new Producer(ss);
		Consumer c = new Consumer(ss);
		new Thread(p).start();

		new Thread(c).start();
	}
}

class WoTou {
	int id; 
	WoTou(int id) {
		this.id = id;
	}
	public String toString() {
		return "WoTou : " + id;
	}
}

class SyncStack {
	int index = 0;
	WoTou[] arrWT = new WoTou[6];
	
	public synchronized void push(WoTou wt) {
		while(index == arrWT.length) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();		
		arrWT[index] = wt;
		index ++;
	}
	
	public synchronized WoTou pop() {
		while(index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();
		index--;
		return arrWT[index];
	}
}

class Producer implements Runnable {
	SyncStack ss = null;
	Producer(SyncStack ss) {
		this.ss = ss;
	}
	
	public void run() {
		for(int i=0; i<20; i++) {
			WoTou wt = new WoTou(i);
			ss.push(wt);
System.out.println("生产了:" + wt);
			try {
				Thread.sleep((int)(Math.random() * 200));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}
	}
}

class Consumer implements Runnable {
	SyncStack ss = null;
	Consumer(SyncStack ss) {
		this.ss = ss;
	}
	
	public void run() {
		for(int i=0; i<20; i++) {
			WoTou wt = ss.pop();
System.out.println("消费了: " + wt);
			try {
				Thread.sleep((int)(Math.random() * 1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}
	}
}

 运行结果:

消费了: WoTou : 0

生产了:WoTou : 0

生产了:WoTou : 1

生产了:WoTou : 2

生产了:WoTou : 3

生产了:WoTou : 4

消费了: WoTou : 4

生产了:WoTou : 5

生产了:WoTou : 6

生产了:WoTou : 7

消费了: WoTou : 7

生产了:WoTou : 8

消费了: WoTou : 8

生产了:WoTou : 9

消费了: WoTou : 9

生产了:WoTou : 10

消费了: WoTou : 10

生产了:WoTou : 11

消费了: WoTou : 11

生产了:WoTou : 12

生产了:WoTou : 13

消费了: WoTou : 12

生产了:WoTou : 14

消费了: WoTou : 13

消费了: WoTou : 14

生产了:WoTou : 15

消费了: WoTou : 15

生产了:WoTou : 16

消费了: WoTou : 16

生产了:WoTou : 17

消费了: WoTou : 17

生产了:WoTou : 18

消费了: WoTou : 18

生产了:WoTou : 19

消费了: WoTou : 19

消费了: WoTou : 6

消费了: WoTou : 5

消费了: WoTou : 3

消费了: WoTou : 2

消费了: WoTou : 1

 

应该是线程出现问题,在push()方法结束后,要打印生产了第几个窝头时,另一线程执行了起来,导致消费在生产之前。

 

修改代码:把打印部分都放进push()和pop()方法内,同时pop()方法返回类型为void。

代码如下:

public class ProducerConsumer {
	public static void main(String[] args) {
		SyncStack ss = new SyncStack();
		Producer p = new Producer(ss);
		Consumer c = new Consumer(ss);
		new Thread(p).start();

		new Thread(c).start();
	}
}

class WoTou {
	int id; 
	WoTou(int id) {
		this.id = id;
	}
	public String toString() {
		return "WoTou : " + id;
	}
}

class SyncStack {
	int index = 0;
	WoTou[] arrWT = new WoTou[6];
	
	public synchronized void push(WoTou wt) {
		while(index == arrWT.length) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();		
		arrWT[index] = wt;
		index ++;
		System.out.println("生产了:" + wt);
	}
	
	public synchronized void pop() {
		while(index == 0) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.notifyAll();
		index--;
		System.out.println("消费了: " + arrWT[index]);
	}
}

class Producer implements Runnable {
	SyncStack ss = null;
	Producer(SyncStack ss) {
		this.ss = ss;
	}
	
	public void run() {
		for(int i=0; i<20; i++) {
			WoTou wt = new WoTou(i);
			ss.push(wt);
			
			try {
				Thread.sleep((int)(Math.random() * 200));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}
	}
}

class Consumer implements Runnable {
	SyncStack ss = null;
	Consumer(SyncStack ss) {
		this.ss = ss;
	}
	
	public void run() {
		for(int i=0; i<20; i++) {
			ss.pop();
			
			try {
				Thread.sleep((int)(Math.random() * 1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}			
		}
	}
}

 

分享到:
评论

相关推荐

    马士兵多线程笔记.zip

    10. **线程间的通信**:Java的BlockingQueue接口和相关的类(如ArrayBlockingQueue、LinkedBlockingQueue)提供了一种线程间通信的方式,允许线程在生产数据和消费数据之间进行协作。 马士兵的多线程训练营资料1和...

    马士兵多线程训练营笔记

    5. **线程通信**:wait()、notify()、notifyAll()方法的使用,以及在生产者消费者模型、哲学家就餐问题等经典示例中的应用。 6. **线程池**:ExecutorService、ThreadPoolExecutor和Future接口的理解,线程池的配置...

    马士兵多线程预习资料.rar

    9. **线程通信**:理解wait()、notify()和notifyAll()方法,以及在生产者消费者模型中的应用。 10. **原子操作与CAS**:学习Atomic类和CompareAndSwap(CAS)算法,以及它们在无锁编程中的应用。 通过学习这份预习...

    马士兵j2se源码和ppt

    总的来说,这个资源包为Java初学者提供了一个全面的学习路径,通过马士兵的专业讲解和源码实例,能够帮助学习者扎实地掌握J2SE,为后续的Java EE和Android开发打下坚实的基础。同时,对于有一定经验的开发者,这些...

    J2SE上半部分_马士兵

    "J2SE上半部分_马士兵"可能是指一个由知名IT教育专家马士兵制作的Java基础教学课程或教材,旨在帮助初学者掌握Java编程的基础知识。 在这个压缩包中,可能包含了马士兵讲解J2SE基础知识的各种资源,如视频教程、...

    马士兵jvm调优笔记.docx

    ### 马士兵JVM调优笔记知识点梳理 #### 一、Java内存结构 Java程序运行时,其内存被划分为几个不同的区域,包括堆内存(Heap)、方法区(Method Area)、栈(Stack)、程序计数器(Program Counter Register)以及...

    马士兵 J2SE代码+PPT教材

    【马士兵 J2SE代码+PPT教材】是针对Java初学者和爱好者提供的一套学习资源,由知名IT教育专家马士兵编著。这套教材涵盖了Java Standard Edition (J2SE) 的核心概念和技术,旨在帮助读者掌握Java编程的基础知识和实践...

    马士兵老师spring框架学习笔记

    马士兵老师是知名的Java教育专家,他的Spring框架学习笔记深入浅出,对于初学者和进阶者来说都是一份宝贵的资源。这份笔记涵盖了Spring的核心概念、配置、AOP(面向切面编程)、DI(依赖注入)等关键知识点。 1. **...

    马士兵老师HashMap学习笔记

    总的来说,马士兵老师的HashMap学习笔记不仅涵盖了HashMap的基础知识,还深入探讨了其在不同JDK版本中的实现细节,特别是并发环境下的问题和解决方案。理解这些内容对于提升Java编程技能和优化代码性能具有重要价值...

    jvm java虚拟机 调优 马士兵 笔记

    jvm java虚拟机 调优 马士兵 笔记 让你对java虚拟机调优有初步的认识

    马士兵 高并发 java架构 预习课 源码

    本课程基于马士兵老师的java高并发编程公开课,深入探讨了多线程在实际应用中的重要性及其使用技巧。通过对源码的分析,我们可以更直观地理解并发控制、线程安全以及性能优化等核心概念。 一、多线程基础 多线程是...

    马士兵oracle笔记

    马士兵oracle笔记,浅显易懂。

    马士兵百万级并发IM即时消息系统

    总结,马士兵百万级并发IM即时消息系统充分利用了Go语言和Gin框架的优势,构建了一个能够处理大规模并发的即时通讯平台。在设计上,系统注重性能优化、安全性、扩展性以及可维护性,确保在高负载下也能提供稳定的...

    Shopping. java 马士兵

    马士兵的教程中,他将带领我们深入理解如何利用Java的Servlet、JSP(JavaServer Pages)以及MVC(Model-View-Controller)设计模式来构建后端逻辑和前端界面。 1. **Servlet与JSP**:Servlet是Java EE中处理HTTP...

    马士兵JAVA笔记(全).docx

    马士兵JAVA笔记(全) 本资源是马士兵的JAVA笔记,涵盖了JAVA语言的基础知识,包括标识符、常量、变量、数据类型、运算符、控制流语句等。 标识符是JAVA中的一种符号,用于命名变量、方法、类等。标识符由字母、...

    马士兵Struts2笔记2013

    Struts2是一个流行的Java web框架,...以上就是"马士兵Struts2笔记2013"中涉及的主要知识点,这些内容涵盖了Struts2的基础配置、数据处理、验证、调试以及与视图层的交互等方面,对于理解和掌握Struts2框架非常有帮助。

    马士兵 html css js源码

    马士兵是一位知名的IT教育专家,他的课程深入浅出,适合初学者和有一定基础的学习者。这个“马士兵 html css js源码”压缩包很可能包含了他在教学过程中用到的各种实例和特效代码,是学习和实践这些技术的宝贵资源。...

    马士兵Shopping项目源代码

    "马士兵Shopping项目"是其精心设计的一个教学实例,旨在帮助学员理解并掌握电商网站的开发流程和技术要点。这个项目源代码的详细分析,将为我们揭示一个完整的购物系统背后的架构设计和实现细节。 1. **项目结构...

    马士兵Python基础版2020教程P98-P134PPT笔记+课堂代码.pdf

    在马士兵的Python基础版2020教程P98-P134部分,我们学习了Python编程中的几个核心概念,包括数据结构、异常处理以及面向对象编程的基础。 1. **列表遍历与嵌套**: 示例代码展示了如何遍历包含字典的列表来查找...

    02-4(马士兵)-多线程并发

    "02-4(马士兵)-多线程并发"可能是一个教学资源,由马士兵老师讲解,涵盖了多线程并发的相关知识。在Java中,Java Util Concurrency (JUC) 工具包提供了强大的并发编程支持,这可能是课程内容的重点。 并发是指系统...

Global site tag (gtag.js) - Google Analytics