如何最好地同步两个在Java中访问一个类的线程

时间:2013-02-01 19:15:02

标签: java multithreading synchronization

我有一个发送SNMP命令并侦听陷阱的程序。

我的第一种方法协调SNMP的发送。一旦他完成发送,我需要他等到他收到收到陷阱的通知,这样他才能继续跑。现在,我试图通过同步全局对象来做到这一点,但它不起作用,我不确定它对我来说是理想的解决方案。

public synchronized int loginUser(ScopedPDU pdu) throws IOException
{

    loginUserManager = new LoginUserManager();

    pdu = buildPdu();   

// send command
        errorStatus = snmpManager.snmpSend(pdu);

        if (errorStatus == SnmpManager.SNMP_PASS)
        {
            // Wait for traps
            synchronized(syncObject)
            {
// read global variable status to see if it's no longer in progress
                while(status == TrapStatus.INPROGRESS)
                {
                    try {
                        System.out.println("Waiting for login to be done");
                        syncObject.wait();
                        System.out.println("We received a notify");
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        } //(errorStatus == SnmpManager.SNMP_PASS)
        else
        {
            return TrapStatus.FAIL;
        }

    System.out.println("Returning status");
    return status;

}

我的第二种方法是接收陷阱(并在与第一种方法不同的线程上运行)并获得我想要的正确状态,但我无法通知另一个线程。

public synchronized void readTrap(Vector v)
{
    Enumeration e = v.elements();

    if(v.contains(PduTrap.UserLoginStatusTrap))
    {
// gets status of login
        status = loginUserManager.getStatus(e);

        synchronized(syncObject)
        {
// notify first method to read the new status
            syncObject.notify();            
        }
    }
        }

status和SyncObject是我试图在线程之间共享的全局类型。我在类构造函数中将状态初始化为INPROGRESS。

private int status;
private Object syncObject;  

有人可以告诉我为什么事情不起作用,或者我是否完全以错误的方式解决这个问题?目前,我的loginUser方法没有被readTrap通知。谢谢

3 个答案:

答案 0 :(得分:0)

您可以考虑共享BlockingQueue,以便readTrap(...)方法add()到队列(可能是新状态?)而loginUser(...)take()从队列中。这样可以处理所有锁定和信令,而无需您进行等待/通知。

在调试代码方面,您需要确保syncObjectprivate final对象,以便等待和通知共享同一个对象引用 。显然,如果他们使用不同的对象,那么您的代码将无法正常工作。

此外,您应该在<{1}}块中设置内的状态。我不确定它在这里有所不同,但对代码至关重要的任何值都应该在互斥块中。您可以考虑在两种方法中打印status的值,以确保它像您想象的那样进行更新。

答案 1 :(得分:0)

这不是执行此类操作的唯一方法,但人们通常会将此类流程视为解决方案。 (我希望这不是那么抽象,以至于没有意义。)

- 方法1 -

  1. 做某事的一部分
  2. 发出其他信号以异步进行某些工作
  3. 在发生某些结果之前什么都不做
  4. 完成您的工作
  5. 将完成状态返回给其他代码。
  6. 它可以这样做,但通常比将其分成两组步骤的其他方式更难。

    - 方法2 -

    A部分

    1. 做某事的一部分
    2. 远离正在进行的工作
    3. 发出其他信号以异步进行某些工作
    4. 忘了它
    5. B部分

      1. 收到通知,告知其他事情已经完成。
      2. 检索正在进行的作品
      3. 完成剩下的工作
      4. 全部完成
      5. 注意一个关键的区别是,第一种方式,你实际上有结果状态,你可以返回到调用这些东西的代码。第二种方式,这两个部分不再同步,你不能这样做。

        您想要做什么取决于来电者的需求。

        可能存在需要执行的SNMP命令列表。如果是这样,您只需要 B部分就可以在完成或标记失败时将其标记在列表中,以便其他人可以重试或通知某人。

        也许对SNMP命令有一个排序,你必须按顺序执行一个,然后按顺序执行另一个。第一种方法适用于此,因为您可以按顺序拨打电话。第二种方法使得更难,因为 Part B 的异步完成必须查找然后启动序列中的下一项。这变得很复杂。

答案 2 :(得分:0)

请将您的syncObject对象作为final(私有Object syncObject = new Object(););请注意synchronized块使用Object引用;因此,如果对象引用发生更改,您将看不到所需的行为。

另外,请从这两个函数中删除synchronized,为什么需要它?如果两个线程都在同一个Object上工作;它可能会导致问题。请注意,synchronized方法使用此引用进行同步。