3

我有一堆线程同时运行。有时一个线程需要通知其他线程等待它完成一个工作并再次发出信号让它们恢复。由于我对 Java 的同步有点陌生,我想知道做这种事情的正确方法是什么。我的代码是这样的:

private void Concurrent() {
    if (shouldRun()) {
        // notify threads to pause and wait for them
        DoJob();
        // resume threads
    }

    // Normal job...
}

更新:

请注意,我编写的代码在一个类中,每个线程都将执行该类。我无权访问这些线程或它们的运行方式。我只是在线程内。

更新 2:

我的代码来自爬虫类。爬虫类(crawler4j)知道如何处理并发。我唯一需要的是在运行一个函数之前暂停其他爬虫,然后再恢复它们。这段代码是我的爬虫的基础:

   public class TestCrawler extends WebCrawler {
    private SingleThread()
    {
        //When this function is running, no other crawler should do anything
    }

    @Override
    public void visit(Page page) {
        if(SomeCriteria())
        {
            //make all other crawlers stop until I finish
            SingleThread();
            //let them resume
        }

        //Normal Stuff
    }
   }
4

3 回答 3

2

这是一个简短的示例,说明如何使用很酷的 java 并发东西来实现这一点:

使用 Pause 类剪断旧代码不再重要。

编辑:

这是新的测试类:

package de.hotware.test;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

    private Pause mPause;

    public Test() {
        this.mPause = new Pause();
    }

    public void concurrent() throws InterruptedException {
        while(true) {
            this.mPause.probe();
            System.out.println("concurrent");
            Thread.sleep(100);
        }
    }

    public void crucial() throws InterruptedException {
        int i = 0;
        while (true) {
            if (i++ % 2 == 0) {
                this.mPause.pause(true);
                System.out.println("crucial: exclusive execution");
                this.mPause.pause(false);
            } else {
                System.out.println("crucial: normal execution");
                Thread.sleep(1000);
            }
        }
    }

    public static void main(String[] args) {
        final Test test = new Test();
        Runnable run = new Runnable() {

            @Override
            public void run() {
                try {
                    test.concurrent();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        };
        Runnable cruc = new Runnable() {

            @Override
            public void run() {
                try {
                    test.crucial();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        };
        ExecutorService serv = Executors.newCachedThreadPool();
        serv.execute(run);
        serv.execute(run);
        serv.execute(cruc);
    }

}

和实用程序暂停类:

package de.hotware.test;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Utility class to pause and unpause threads
 * with Java Concurrency
 * @author Martin Braun
 */
public class Pause {

    private Lock mLock;
    private Condition mCondition;
    private AtomicBoolean mAwait;

    public Pause() {
        this.mLock = new ReentrantLock();
        this.mCondition = this.mLock.newCondition();
        this.mAwait = new AtomicBoolean(false);
    }

    /**
     * waits until the threads until this.mAwait is set to true
     * @throws InterruptedException
     */
    public void probe() throws InterruptedException {
        while(this.mAwait.get()) {
            this.mLock.lock();
            try {
                this.mCondition.await();
            } finally {
                this.mLock.unlock();
            }
        }
    }

    /**
     * pauses or unpauses
     */
    public void pause(boolean pValue) {
        if(!pValue){
            this.mLock.lock();
            try {
                this.mCondition.signalAll();
            } finally {
                this.mLock.unlock();
            }
        }
        this.mAwait.set(pValue);
    }

}

基本用法是在每次运行之前调用 probe()。如果在调用 pause(false) 之前暂停,这将阻塞。

您的课程将如下所示:

public class TestCrawler extends WebCrawler {

private Pause mPause;

public TestCrawler(Pause pPause) {
    this.mPause = pPause;
}

private SingleThread()
{
        //When this function is running, no other crawler should do anything
}

@Override
public void visit(Page page) {
    if(SomeCriteria())
    {
        //only enter the crucial part once if it has to be exclusive
        this.mPause.probe();
        //make all other crawlers stop until I finish
        this.mPause.pause(true);
        SingleThread();
        //let them resume
        this.mPause.pause(false);
    }
    this.mPause.probe();
    //Normal Stuff
}
}
于 2013-01-13T14:11:49.510 回答
1
public class StockMonitor extends Thread {

    private boolean suspend = false; 
    private volatile Thread thread;

    public StockMonitor() {
        thread = this;
    }

    // Use name with underscore, in order to avoid naming crashing with
    // Thread's.
    private synchronized void _wait() throws InterruptedException {
        while (suspend) {
            wait();
        }
    }

    // Use name with underscore, in order to avoid naming crashing with
    // Thread's.
    public synchronized void _resume() {
        suspend = false;
        notify();
    }

    // Use name with underscore, in order to avoid naming crashing with
    // Thread's.
    public synchronized void _suspend() {
        suspend = true;
    }  

     public void _stop() { 
        thread = null;
        // Wake up from sleep.
        interrupt();     
     }

     @Override
     public void run() {
        final Thread thisThread = Thread.currentThread();
        while (thisThread == thread) {
            _wait();
            // Do whatever you want right here.
        }
     }
}

调用_resumeand_suspend将使您能够恢复和暂停Thread. _stop会让你优雅地停止线程。请注意,一旦停止Thread,就无法再次恢复它。Thread不再可用。

该代码是从一个真实世界的开源项目中挑选出来的:http: //jstock.hg.sourceforge.net/hgweb/jstock/jstock/file/b17c0fbfe37c/src/org/yccheok/jstock/engine/RealTimeStockMonitor.java#l247

于 2013-01-13T13:52:23.783 回答
0

您可以使用 wait() 和 notify()

线程等待:

  // define mutex as field
  Object mutex = new Object();

   // later:
   synchronized(mutex) {
        wait();
   }

通知线程继续

   synchronized (mutex) {
        notify();
   }
于 2013-01-13T13:49:28.683 回答