首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

菜鸟:多线程碰到的纠结有关问题

2013-09-04 
初学者:多线程碰到的纠结问题首先,请看我的代码:package clone/** * 生产者与消费者的问题 */import java

初学者:多线程碰到的纠结问题
首先,请看我的代码:

package clone;

/**
 * 生产者与消费者的问题
 */
import java.util.*;
public class Run{
public static void main(String[]args){
Producer p = new Producer();
Consumer c = new Consumer();
new Thread(p,"p").start();//start时就会调用produce()
new Thread(c,"c").start();//start时就会调用consumption()
}
}

class Producer implements Runnable{
public Producer(){
if( null == goods ) goods = new ArrayList<Goods>();
}
@Override
public void run(){
try{
synchronized(this){
produce();
}
}
catch(Exception err){err.printStackTrace();}
}
public void produce() throws Exception{//生产
System.out.println("coming ! the current thread is "+Thread.currentThread().getName());
int size = goods.size()+1 ;
String name = String.valueOf(size);
goods.add(new Goods(size , name ,Double.parseDouble(name))) ;
System.out.println(goods.size());
}
private static List<Goods> goods;
public static List<Goods> obtainedGoods(){ 
System.out.println(Thread.currentThread().getName()+":"+goods.size());return goods ; }
}

class Consumer implements Runnable{
@Override
public void run(){
try{
synchronized(this){
consumption();
}
}
catch(Exception err){err.printStackTrace();}
}
public void consumption(){//消费
System.out.println("coming ! the current thread is "+Thread.currentThread().getName());
goods = Producer.obtainedGoods();
if( null == goods ) System.out.println(Thread.currentThread().getName()+":"+"do not have this kind of goods !");
if( 0 == goods.size() ) System.out.println(Thread.currentThread().getName()+":"+"this goods have been done not have !");
else{
Goods g;
int i = goods.size() ;
while( 0 != i ){
g = (Goods)goods.get(i-1);
g.displays();
i -- ;
}
}
}
private List<Goods> goods;
}

class Goods{//商品类
private int id ;
private String name = "goods";
private double price ;
public Goods(int id , String name , double price){this.id = id ; this.name = this.name+name ; this.price = price ;}


public void displays(){//显示商品
System.out.println(Thread.currentThread().getName()+":"+"id="+id+", name="+name+", price"+price);
}
}



这个程序中,我在 run() 方法里面加了同步操作,那么,一旦进入了程序,就会执行下去,知道完毕后交给别的线程执行!

所以,我预计,这个程序只有两种情况,
情况1、若p先执行,必须先执行produce(),然后结束p后,才能执行c,则理论上应该出现:
        coming ! the current thread is p //先输出看看是哪个线程
        1                                //执行了produce(),此时goods.size() == 1
        coming ! the current thread is c //接着执行c
        c:1                              //得到的goods的大小size() 肯定也是 1
        c:id=1, name=goods1, price1.0    //displays()显示结果

情况2、若c先执行,必须先执行consumption(),然后结束c,再执行p,则理论上应该出现:
        coming ! the current thread is c        //先输出看看是哪个线程
        c:0                                     //执行了produce(),此时goods.size() == 1
        c:this goods have been done not have !  //先消费,肯定没数据咯!
        coming ! the current thread is p        //执行p,进入produce(),打印线程信息
        1                                       //goods生产一笔数据了

-----------------------

可惜,这只是我的理想状态!!!
现实中,的确,我的两种情况出现了!!!
但是,还出现了其他情况,如下:
coming ! the current thread is p
coming ! the current thread is c
c:0
c:this goods have been done not have !
1

我就怪了,我都同步了,怎么还能够进入了p线程后,突然p去休息了,c线程上了,之后又p!!!
很怪很纠结 !!!
求解答


[解决办法]

引用:
首先,请看我的代码:
package clone;
....


请注意以下代码
[code=java]
synchronized(this){
}

Producer和Consumer都是对this进行同步的,而它们是不同的对象,这就是主要原因。

使用相同的locker对象可以解决问题

synchronized(Run.class) {
}



[解决办法]
synchronized(this)
是指锁定当前对象。你这里的当前对象有两个,一个是p,另一个是c。
线程1锁了p,线程2锁了c.两个线程并没有实现同步。你要实现两个线程的同步,必须锁住一个公用资源。楼上的使用Run.class,这个是一个特殊对象,整个虚拟机中只存在一份。
[解决办法]
引用:
Quote: 引用:

。。。。。


你的意思我理解了,但还有最后一个问题:
比如,就刚刚的代码,如果synchronized(Run.class){ produce();},去掉synchronized,而把方法public void produce()改成public synchronized void produce(),
那么程序照样不行,这又是为什么,
难道 modifier synchronized returnType method(),就相当于synchronized(this){ ...}
???


public synchronized void produce()

等同于

public void produce() {
synchronized(this){ ...}
}

热点排行