继文章:
【线程同步】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接口实现资源共享中,只是创建了一个线程。
题外话结束