为什么同步不起作用? [英] Why is synchronized not working?

查看:67
本文介绍了为什么同步不起作用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个方法,该方法要求设备输入然后接受响应,所有这些都是原子操作.

I am trying to write a method that asks a device for input and then accepts a response, all as an atomic operation.

这是我的代码(query 方法才是真正应该关注的):

Here is my code (the query method is really what should be focused on):

public class DeviceConnection implements Runnable{
    //For query
    static int test = 0;

    //For writeline
    static PrintWriter out = null; //(initialized in constructor)

    //Only important for readline
    static String[] systemMessage=new String[10];
    static int messageIn=0;
    static int messageOut=0;
    static boolean connected = false;
    static boolean endConnect = true;

    static PrintStream logWriter; //(initialized in constructor)
    static String serverName="";//(initialized in constructor)
    static int socketNum;//(initialized in constructor)

    /** REALLY ONLY NEED TO LOOK AT THIS METHOD
         * Atomic operation to ask for data from device
         * and get a response.
         * @param line -    query to be passed to device
         * @return response from device
         */
    public synchronized String query(String line){
        int temp = test;
        System.err.print("foo" + test);
        System.err.print(this);
        String response;
        writeLine(line);
        response = readLine();
        System.err.println("bar" + test + " should be " + temp);
        test = temp+1;
        return response;
    }


/**
     * Writes a query to the device. 
     *<p>
     * Does <b>not</b> get or handle any response
     * @param line -    query to be passed to device
     */
    public synchronized void writeLine(String line) {
        out.println(line + "\n");
    }

/**
     * Reads a response from device.
     *<p>
     * Should never be used outside of <code>query</code>
     * as this could create a race condition if another
     * thread is writing to the device at the same time.
     * @return
     */
    private synchronized String readLine() {

        String response;
        long start, stop;

        if (messageIn != messageOut) { // new message exists
            response = systemMessage[messageOut];
            messageOut = (messageOut + 1) % 10;
        } else {
            start = System.currentTimeMillis();
            try {
                if (connected) { // if connected wait for heatbeats
                    //wait(15000);
                    wait();
                    start = System.currentTimeMillis();
                } else { // if not connected ignore heartbeats
                    wait();
                    start = System.currentTimeMillis();
                }
            } catch (InterruptedException e) { return "Interrupted"; }
            stop = System.currentTimeMillis();

            if (stop - start < 12000) { // heart beats running at 5 s
                if (messageIn != messageOut) { // new message exists
                    response = systemMessage[messageOut];
                    messageOut = (messageOut + 1) % 10;
                } else {
                    return null;
                }
            } else { // heart beats lost
                response = "Heart beats lost";
                logWriter.println(response);
                if (connected) { // connection lost on client side
                    logWriter.println("Connection to " + serverName + 
                                      " lost on client side");
                    sleep(60000);
                    connect(serverName,socketNum);
                }
            }
        }
        return response;
    }
}

通常 query 方法运行良好,但有时我会得到这样的输出:

Usually the query method runs fine, but sometimes I get output like so:

foo59lib.DeviceConnection@7bd0bf6d(other System.out stuff printed here)
foo59lib.DeviceConnection@7bd0bf6dbar59 should be 59
bar60 should be 59

这怎么可能?对象上的方法不是锁定/同步的吗?该对象显然与打印显示相同,但​​不知何故同时执行了两个 query 方法.

How is this possible? Aren't the methods locked/synchronized on the object? The object is clearly the same as the prints show, but somehow two query methods are being executed simultaneously.

推荐答案

你的 readLine 方法,从 query 调用,调用 wait,它释放锁,它将允许另一个线程同时调用 query.

Your readLine method, which is called from query, calls wait, which releases the lock, which would enable another thread to call query concurrently.

您应该始终使用条件变量在循环内调用 wait,您使用 if 来决定是否等待的模式是有缺陷的.一旦您的线程重新获取锁,它就需要检查当前状态.

You should always call wait inside a loop using a condition variable, your pattern of using an if to decide whether to wait is flawed. Once your thread reacquires the lock it needs to check what the current state is.

wait 释放锁定在 Object#wait:

That wait releases the lock is explained in the documentation for Object#wait:

当前线程必须拥有这个对象的监视器.线程释放此监视器的所有权并等待另一个线程通知等待此对象监视器的线程唤醒通过调用 notify 方法或 notifyAll 方法.这线程然后等待,直到它可以重新获得监视器的所有权和恢复执行.

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

与单参数版本一样,中断和虚假唤醒是可能,并且这个方法应该总是在循环中使用:

As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:

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

这篇关于为什么同步不起作用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆