Concurrent Programming in Java 才翻5页就充满疑惑的代码,大家帮忙分析分析

04-11-01 newjoy
书上说这段代码解决了并发问题:但我横看竖看还是有问题呀:

import java.util.Random;

class Particle{
  protected int x;
  protected int y;
  protected final Random rng = new Random();

  public Particle(int inX,int inY){
    x = inX;
    y = inY;
  }

  public synchronized void move(){
    x += rng.nextInt(10) - 5 ;
    y += rng.nextInt(20) - 10;
  }

  public void draw(Graphics g){
    int lx,ly;
    synchronized (this) {lx=x;ly=y;}
    g.drawRect(lx,ly,10,10);
  }
}
<p>

1、由于 move() 与 draw(Graphics g) 方法可能会被两个线程同时调用,那它还是没有解决,“当draw操作使用move方法调用前的y值和move方法调用后的x值绘制一个例子的图形”。

2、protected final Random rng = new Random(); 为什么定义为final?好处具体表现在什么地方?

Azure_2003
2004-11-02 11:33
> 1、由于 move() 与 draw(Graphics g)

> 方法可能会被两个线程同时调用,那它还是没有解决,“当dr

> w操作使用move方法调用前的y值和move方法调用后的x值绘制?> 个例子的图形”。

不太明白这段程序要解决的是哪方面的并发,“当draw操作使用move方法调用前的y值和move方法调用后的x值绘制一个例子的图形”。这句话让人不太理解。

>

> 2、protected final Random rng = new Random();

> 为什么定义为final?好处具体表现在什么地方?

个人理解为:定义为final是为了强制让Particle类的一个实例中只能使用一个rng引用,不允许被转移引用指针,也不允许被null,直到该Particle实例被释放时rng引用才被释放掉. 这么做的目的主要是为了程序逻辑上的安全,当然如果你的记忆力比较好,或者你不想多为将来接受这个程序的人做奉献,要不要final都是一样的.

newjoy
2004-11-02 12:08
不好意思,写错两个字

“当draw操作使用move方法调用前的y值和move方法调用后的x值绘制一个粒子的图形”。

这儿的并发问题是,若move方法和draw方法同时被连个线程调用。

有可能发现这样的现象:

1、draw 准备绘图时,先获取一个X,

2、同时,move,修改了 x,y的值

4、draw 获取Y,这是获取的X,Y不是一致性的。 只会在一个错误的点显示一个图形。

所以说“当draw操作使用 move方法调用前的y值和move方法调用后的x值绘制一个粒子的图形”。

newjoy
2004-11-02 12:09
不好意思,写错两个字

“当draw操作使用move方法调用前的y值和move方法调用后的x值绘制一个粒子的图形”。

这儿的并发问题是,若move方法和draw方法同时被两个线程调用。

有可能发现这样的现象:

1、draw 准备绘图时,先获取一个X,

2、同时,move,修改了 x,y的值

4、draw 获取Y,这是获取的X,Y不是一致性的。 只会在一个错误的点显示一个图形。

所以说“当draw操作使用 move方法调用前的y值和move方法调用后的x值绘制一个粒子的图形”。

Azure_2003
2004-11-02 13:33
你的担心是多余的:

synchronized (this) {lx=x;ly=y;}
<p>

这里上的对象锁,锁定对象是this,所以在此锁定的工作区域里面操作的时候是不允许其它线程move()的,直到该锁定区域运行完毕,这时候this实例上的对象锁就被释放掉了.move()操作就可以被执行了.

而在move()动作上有一个方法锁,在此方法操作的时候是不允许x值和y值被两个线程乱改的.

因为在写的时候x,y是一致的,而在读的时候该x,y又不允许被修改,所以说它解决了你所担心的这个并发问题

newjoy
2004-11-02 15:58
谢谢!

多线程我要补补课啦 :)

newjoy
2004-11-02 16:17
那我要想问个问题,下面的代码:

public class QueueThread extends Thread {

  private static Logger logger = Logger.getLogger(QueueThread.class.getName());

  private PacketQueue packetQueue;
  private HashMap packetListeners = new HashMap();

  public QueueThread(PacketQueue queue) { packetQueue = queue;  }

  public boolean addListener(PacketListener listener, String element){
    if (listener == null || element == null){
      return false;
    }
    packetListeners.put(listener,element);
    return true;
  }

  public boolean removeListener(PacketListener listener){
    packetListeners.remove(listener);
    return true;
  }

  public void run(){

    for( Packet packet = packetQueue.pull();
         packet != null;
         packet = packetQueue.pull()) {

      logger.finest("Get One Packet:" + packet);
      try {
        Packet child;
        String matchString;
        if (packet.getElement().equals("iq")){
          child = packet.getFirstChild("query");
          if (child == null){
            matchString = "iq";
          } else {
            matchString = child.getNamespace();
          }
        } else {
          matchString = packet.getElement();
        }

        synchronized(packetListeners){
          Iterator iter = packetListeners.keySet().iterator();
          while (iter.hasNext()){
            PacketListener listener = (PacketListener)iter.next();
            String listenerString = (String)packetListeners.get(listener);
            if (listenerString.equals(matchString)){
              listener.notify(packet);
            }
          }
        }
      } catch (Exception ex){
        //Log.error("QueueThread: ", ex); // Soldier on - no matter what
      }
    }
  }
}

<p>

一旦任意线程进入

 synchronized(packetListeners){
          Iterator iter = packetListeners.keySet().iterator();
          while (iter.hasNext()){
            PacketListener listener = (PacketListener)iter.next();
            String listenerString = (String)packetListeners.get(listener);
            if (listenerString.equals(matchString)){
              listener.notify(packet);
            }
          }
        }
<p>

代码块,则别的线程调用函数

public boolean addListener(PacketListener listener, String element){
    if (listener == null || element == null){
      return false;
    }
    packetListeners.put(listener,element);
    return true;
  }
<p>

执行到

packetListeners.put(listener,element);
处一定是阻塞状态对不?

Azure_2003
2004-11-02 17:47

猜你喜欢