notify()和wait()不能在Java中工作

时间:2015-12-15 14:14:55

标签: java multithreading wait notify

我有2个线程,我想与wait()和notify()同步。但是,当我通知等待永远不会恢复的线程时。这是我的代码片段。 在Lib60870中,我启动两个线程,并且线程HandShake与SerialReader同步。

public Lib60870(){ //Here I start threads
    try {
        myConnection=new Connection(LOCALHOST,port);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    mySerialReader.start();
    myHandshake.start();}
}

类SerialReader

public class SerialReader extends Thread {

private static boolean isPaused=true;

@Override
public void run() {
    synchronized(this){
        if(Lib60870.myConnection!=null){
            while(true){
                if(!isPaused){
                    byte inByte=Lib60870.myConnection.getByte();
                    if(inByte==0x68){
                        ...
                        }
                        notify();
                    }
                    else if(inByte==0x10){
                        ...         
                        }
                        notify();
                    }
                }
            }
        }
    }
}

public void setPause(boolean pause){
    isPaused=pause;
}

班级握手

public class HandShake extends Thread {


public void run() {
    synchronized(Lib60870.mySerialReader){
        Lib60870.mySerialReader.setPause(false);
        ...
        try {
            Lib60870.mySerialReader.wait();
        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        Lib60870.mySerialReader.setPause(true);
        ...
        Lib60870.mySerialReader.setPause(false);
        try {
            Lib60870.mySerialReader.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

}

提前致谢

2 个答案:

答案 0 :(得分:1)

您的方法存在许多问题:

  1. 扩展Thread被视为不良做法。
  2. 使用wait / notify可以使用java.util.concurrent中的某些内容完成某项操作并不是一个好主意。
  3. 陷入紧密旋转的循环不会暂停。
  4. 这是一个可暂停的线程类。给自己写一个Stepper对象并使用其中一个来连续执行step()方法而不是暂停。使用其pause / resume方法将其暂停。

    /**
     * PauseableThread is a Thread with pause/resume and cancel methods.
     *
     * The meat of the process must implement `step`.
     *
     * You can either extend this and implement `step` or use the factory.
     *
     * I cannot extend Thread because my resume will clash.
     *
     */
    public abstract class PauseableThread implements Runnable {
    
        // The lock.
        private final ReadWriteLock pause = new ReentrantReadWriteLock();
        private final Lock readLock = pause.readLock();
        private final Lock writeLock = pause.writeLock();
        // Flag to cancel the whole process.
        private volatile boolean cancelled = false;
        // The exception that cause it to finish.
        private Exception thrown = null;
        // The thread that is me.
        private Thread me = null;
    
        @Override
        // The core run mechanism.
        public void run() {
            // Track my current thread.
            me = Thread.currentThread();
            try {
                while (!finished()) {
                    // Block here if we're paused.
                    blockIfPaused();
                    // Don't do any more work if we've been asked to stop.
                    if (!finished()) {
                        // Do my work.
                        step();
                    }
                }
            } catch (Exception ex) {
                // Just fall out when exception is thrown.
                thrown = ex;
            }
        }
    
        // Have we finished yet?
        private boolean finished() {
            return cancelled || me.isInterrupted();
        }
    
        // Block if pause has been called without a matching resume.
        private void blockIfPaused() throws InterruptedException {
            try {
                // Grab a write lock. Will block if a read lock has been taken - i.e. we've been paused.
                writeLock.lockInterruptibly();
            } finally {
                // Release the lock immediately to avoid blocking when pause is called.
                writeLock.unlock();
            }
        }
    
        // Pause the work. NB: MUST be balanced by a resume.
        public void pause() {
            // We can wait for a lock here.
            readLock.lock();
        }
    
        // Resume the work. NB: MUST be balanced by a pause.
        public void resume() {
            // Release the lock.
            readLock.unlock();
        }
    
        // Stop.
        public void cancel() {
            // Stop everything.
            cancelled = true;
        }
    
        // Stop immediately (if param is true).
        public void cancel(boolean interrupt) {
            if (interrupt) {
                // Interrupt me.
                me.interrupt();
            } else {
                // Or cancel me.
                cancel();
            }
        }
    
        // Wait for completion.
        public void await() throws InterruptedException {
            // Wait 'till we've finished. NB: Will wait forever if you haven't instigated a cancel of some kind.
            while (me.isAlive()) {
                Thread.sleep(0);
            }
        }
    
        // Start - like a thread.
        public void start() {
            // Wrap me in a thread and fire the sucker up!
            new Thread(this).start();
        }
    
        // Get the exception that was thrown to stop the thread or null if the thread was cancelled.
        public Exception getThrown() {
            return thrown;
        }
    
        // Expose my Thread.
        public Thread getThread() {
            return me;
        }
    
        // Create this method to do stuff.
        // Calls to this method will stop when pause is called.
        // Any thrown exception stops the whole process.
        public abstract void step() throws Exception;
    
        // Factory to wrap a Stepper in a PauseableThread
        public static PauseableThread make(Stepper stepper) {
            StepperThread pauseableStepper = new StepperThread(stepper);
            // That's the thread they can pause/resume.
            return pauseableStepper;
        }
    
        // One of these must be used.
        public interface Stepper {
    
            // A Stepper has a step method.
            // Any exception thrown causes the enclosing thread to stop.
            public void step() throws Exception;
        }
    
        // Holder for a Stepper.
        private static class StepperThread extends PauseableThread {
    
            // The actual stepper I am proxying.
            private final Stepper stepper;
    
            StepperThread(Stepper stepper) {
                this.stepper = stepper;
            }
    
            @Override
            public void step() throws Exception {
                stepper.step();
            }
        }
    
        // !!!! Testing only below !!!!
        // My test counter.
        static int n = 0;
    
        // Test/demo.
        public static void main(String[] args) throws InterruptedException {
    
            try {
                // Simple stepper that just increments n.
                Stepper s = () -> {
                    n += 1;
                    Thread.sleep(1);
                };
                PauseableThread pt = PauseableThread.make(s);
                // Start it up.
                pt.start();
                Thread.sleep(1000);
                pt.pause();
                System.out.println("Paused: " + n);
                Thread.sleep(1000);
                System.out.println("Resuminng: " + n);
                pt.resume();
                Thread.sleep(1000);
                pt.cancel();
                pt.await();
                System.out.println("Finished: " + n);
    
                // Start again to test agressive cancelling.
                n = 0;
                pt = PauseableThread.make(s);
                // Start it up.
                pt.start();
                Thread.sleep(1000);
                pt.pause();
                System.out.println("Paused: " + n);
                Thread.sleep(1000);
                System.out.println("Resuminng: " + n);
                pt.resume();
                Thread.sleep(1000);
                // Cancel aggressively.
                pt.cancel(true);
                pt.await();
                System.out.println("Finished: " + n);
                System.out.println("thrown: " + pt.getThrown());
    
            } catch (InterruptedException e) {
            }
        }
    }
    

答案 1 :(得分:0)

您遇到的主要问题是只有一个线程可以锁定。这意味着当你的notify()线程持有锁时,没有其他线程可以在持有该锁的代码块中运行。

将同步块移动到if (isPaused)块内,以便另一个线程可以在其间运行。

你遇到的另一个问题是你的isPaused布尔值不是易变的,因此可以内联,即它可能永远不会停止。它不应该是静态的,即使你知道你将永远不会有这些,这对于实例变量使用静态字段是不好的做法。

暂停时,应该让CPU休眠。

每当你通知()或notifyAll()时,这应该导致状态改变,你的wait()应该总是检查状态的变化。