【线程同步2】java实现生产者消费者问题$扩展,出现的问题,思考

继文章:

【线程同步】java实现生产者消费者问题与线程中的wait与notify总结 - robert_lizhiqiang的专栏 - 博客频道 - CSDN.NET
http://blog.csdn.net/robert_lizhiqiang/article/details/39292271

之后,总结了两个方法的使用,于是把P—C模式又编写了一次,这次编写,没有使用extends Thread 的方式,而是实现了Runnable接口。并且两个类并没有在Main的内部类

里面。

刚写版本一的如下:

package tmppkg;

import java.util.LinkedList;

public class MyProducerConsumer2 {
	private static LinkedList<Object> storeHouse = new LinkedList<Object>();
	public static final int MAX = 10;

	public static void main(String[] args) {

		new MyProducerConsumer2().start();
	}

	private void start() {

		Producer producer = new Producer();
		Consumer consumer = new Consumer();
		Thread producerThread = new Thread(producer, "producer");
		Thread consumerThread = new Thread(consumer, "consumer");
		producerThread.start();
		consumerThread.start();
		

	}

	class Producer extends Thread {

		public void run() {
				// TODO Auto-generated method stub
				synchronized (storeHouse) {
					try {
						while (storeHouse.size() > MyProducerConsumer2.MAX) {
							System.out
									.println("the storeHouse's size are full, please wait...");

							storeHouse.wait();

						}
						boolean isAddOk = storeHouse.add(new Object());
						if (isAddOk) {
							System.out
									.println(Producer.class
											+ " add a new object to the store house, please eat it...");
							Thread.sleep((long) Math.random() * 3000);
							storeHouse.notify();

						}
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						System.out
								.println("the storeHouse's size are full, and it is be interrupted!");
					}

				}

		}

	}

	class Consumer extends Thread {

		public void run() {

				// TODO Auto-generated method stub
				synchronized (storeHouse) {
					try {
						while (storeHouse.size() == 0) {
							System.out
									.println("there is no object in store house, I'm hungry...");
							storeHouse.wait();
						}
						storeHouse.removeLast();
						System.out
								.println(Consumer.class
										+ " eat a object from store house, please add one...");
						Thread.sleep((long) Math.random() * 3000);
						storeHouse.notify();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

				}

		}

	}
}

运行结果:

class tmppkg.MyProducerConsumer2$Producer add a new object to the store house, please eat it...
class tmppkg.MyProducerConsumer2$Consumer eat a object from store house, please add one...

百思不得其解,为什么就运行了两行不进行下去了,一直以为是C类出现的问题

后来和标准的一对比,知道了,少了while(true)

原来同步的意义在于此!!!

(刚无意发现,按ESC可以全屏编写)

于是改进如下:

但是发现运行后,速度超级快,跟本不是慢慢的一个一个来。应该是Thread.sleep中的时间问题

果然,应该写成:

Thread.sleep((long) (Math.random() * 3000))

而不是

Thread.sleep((long) Math.random() * 3000)

有趣的是,我把C改成了正确的,P没改,就出现了if(full)的情况,这样当然算正确了,因为在10以内都的正确。

如下:

import java.util.LinkedList;

public class MyProducerConsumer {
	public static LinkedList<Object> storeHouse = new LinkedList<Object>();
	public static final int MAX = 10;

	public static void main(String[] args) {

		new MyProducerConsumer().start();
	}

	private void start() {
		Producer producer = new Producer();
		Consumer consumer = new Consumer();
		Thread producerThread = new Thread(producer, "producer");
		Thread consumerThread = new Thread(consumer, "consumer");
		producerThread.start();
		consumerThread.start();
	}

}

class Producer implements Runnable {

	public void run() {
		while (true) {

			// TODO Auto-generated method stub
			synchronized (MyProducerConsumer.storeHouse) {
				while (MyProducerConsumer.storeHouse.size() >= MyProducerConsumer.MAX) {
					System.out
							.println("the storeHouse's size are full, please wait...");
					try {
						MyProducerConsumer.storeHouse.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						System.out
								.println("the storeHouse's size are full, and it is be interrupted!");
					}
				}
				boolean isAddOk = MyProducerConsumer.storeHouse
						.add(new Object());
				if (isAddOk) {
					System.out
							.println(Producer.class
									+ " add a new object to the store house, please eat it...");
					try {
						Thread.sleep((long) Math.random() * 3000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						System.out.println(Producer.class
								+ " sleep failed! please check it out....");
					}
					MyProducerConsumer.storeHouse.notify();

				}
			}

		}
	}

}

/*
 * synchronized (obj) { while (<condition does not hold>) obj.wait(); ... //
 * Perform action appropriate to condition }
 */
class Consumer implements Runnable {

	public void run() {
		while (true) {

			// TODO Auto-generated method stub
			synchronized (MyProducerConsumer.storeHouse) {
				try {
					while (MyProducerConsumer.storeHouse.size() == 0) {
						System.out
								.println("there is no object in store house, I'm hungry...");
						MyProducerConsumer.storeHouse.wait();
					}
					MyProducerConsumer.storeHouse.removeLast();
					System.out
							.println(Consumer.class
									+ " eat a object from store house, please add one...");
					// Thread.sleep((long) Math.random() * 3000);
					Thread.sleep((long) (Math.random() * 3000));

					MyProducerConsumer.storeHouse.notify();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}

		}
	}

}

运行结果如下(刚开始出现了11个是因为在代码
MyProducerConsumer.storeHouse.size() >= MyProducerConsumer.MAX
中写成了>,后来加上=就正常了):

class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
class Producer add a new object to the store house, please eat it...
the storeHouse's size are full, please wait...
class Consumer eat a object from store house, please add one...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
class Producer add a new object to the store house, please eat it...
class Consumer eat a object from store house, please add one...
至此,明白了:

1、同步其实是在加了syn关键字后,才算同步。

2、对于同步不结束的线程,加上了while(true)才算真正意义上的P-C模式。

3、其它一些小问题,例如sleep的问题,要改正。

4、其实对于同步来说,不管是extends Thread方式,还是实现Runnable接口的方式,结果都是一样的,只要按照API来写就正常。当然我更prefer实现接口。

5、对于同步来说,内部类和外部类并没有关系。

6、对于同步来说,同步的obj(在本例中是storeHouse)是否是成员变量,和是否是静态变量,没有关系。


题外话:


对于启动线程,是否启动了一种线程还是启动了多线程,得益于某网友一个错误的博客:

java多线程总结 - Rollen Holt - 博客园
http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html

中的一段:

引用如下————————————————————————————————————————————————————————————————————————————————————————————————————————

关于选择继承Thread还是实现Runnable接口?

其实Thread也是实现Runnable接口的

1
2
3
4
5
6
7
8
class  Thread implements  Runnable {
     //…
public  void  run() {
         if  (target != null ) {
              target.run();
         }
         }
}

其实Thread中的run方法调用的是Runnable接口的run方法。不知道大家发现没有,Thread和Runnable都实现了run方法,这种操作模式其实就是代理模式。关于代理模式,我曾经写过一个小例子呵呵,大家有兴趣的话可以看一下:http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144847.html

Thread和Runnable的区别:

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
  * @author Rollen-Holt 继承Thread类,不能资源共享
  * */
class  hello extends  Thread {
     public  void  run() {
         for  ( int  i = 0 ; i < 7 ; i++) {
             if  (count > 0 ) {
                 System.out.println( "count= "  + count--);
             }
         }
     }
 
     public  static  void  main(String[] args) {
         hello h1 = new  hello();
         hello h2 = new  hello();
         hello h3 = new  hello();
         h1.start();
         h2.start();
         h3.start();
     }
 
     private  int  count = 5 ;
}

 

【运行结果】:

count= 5

count= 4

count= 3

count= 2

count= 1

count= 5

count= 4

count= 3

count= 2

count= 1

count= 5

count= 4

count= 3

count= 2

count= 1

大家可以想象,如果这个是一个买票系统的话,如果count表示的是车票的数量的话,说明并没有实现资源的共享。

我们换为Runnable接口

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class  MyThread implements  Runnable{
 
     private  int  ticket = 5 //5张票
 
     public  void  run() {
         for  ( int  i= 0 ; i<= 20 ; i++) {
             if  ( this .ticket > 0 ) {
                 System.out.println(Thread.currentThread().getName()+ "正在卖票" + this .ticket--);
             }
         }
     }
}
public  class  lzwCode {
     
     public  static  void  main(String [] args) {
         MyThread my = new  MyThread();
         new  Thread(my, "1号窗口" ).start();
         new  Thread(my, "2号窗口" ).start();
         new  Thread(my, "3号窗口" ).start();
     }
}

 

  

 

 

【运行结果】:

count= 5

count= 4

count= 3

count= 2

count= 1

 

总结一下吧:

实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

 

所以,本人建议大家劲量实现接口。

引用结束————————————————————————————————————————————————————————————————————————————————————————————————————————

这段他是错误的。

总结1也是错误的。

解释如下:

class hello extends Thread {
public void run() {
for (int i = 0; i < 7; i++) {
if (count > 0) {
System.out.println("count= " + count--);
}
}
}

public static void main(String[] args) {
helloh1 = new hello();
helloh2 = new hello();
helloh3 = new hello();
h1.start();
h2.start();
h3.start();
}

private int count = 5;
}
这个继承Thread实现的方法,在main方法中其实是创建了是三个线程,所以运行的时候输出的是15条记录。但是如下实例:

private int ticket = 5; //5张票

public void run() {
for (int i=0; i<=20; i++) {
if (this.ticket > 0) {
System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);
}
}
}
}
public class lzwCode {

public static void main(String [] args) {
MyThreadmy = new MyThread();
new Thread(my, "1号窗口").start();
new Thread(my, "2号窗口").start();
new Thread(my, "3号窗口").start();
}
}
这个是通过实现Runnable接口实现资源共享中,只是创建了一个线程。

题外话结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不止鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值