如何在Java中发出线程安全的暂停信号
我有一堆线程同时运行。有时,一个线程需要通知其他线程等待它完成一个作业,并再次发出信号让它们继续。由于我对Java的同步有些陌生,我想知道做这种事情的正确方法是什么。我的代码是这样的:如何在Java中发出线程安全的暂停信号,java,multithreading,synchronization,Java,Multithreading,Synchronization,我有一堆线程同时运行。有时,一个线程需要通知其他线程等待它完成一个作业,并再次发出信号让它们继续。由于我对Java的同步有些陌生,我想知道做这种事情的正确方法是什么。我的代码是这样的: private void Concurrent() { if (shouldRun()) { // notify threads to pause and wait for them DoJob(); // resume threads }
private void Concurrent() {
if (shouldRun()) {
// notify threads to pause and wait for them
DoJob();
// resume threads
}
// Normal job...
}
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
}
}
更新:
请注意,我编写的代码位于一个类中,每个线程都将执行该类。我无法访问这些线程,也无法访问它们的运行方式。我只是内线
更新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
}
}
您可以使用wait()和notify()
线程等待:
// define mutex as field
Object mutex = new Object();
// later:
synchronized(mutex) {
wait();
}
通知线程继续
synchronized (mutex) {
notify();
}
调用\u resume
和\u suspend
将使您能够继续并暂停线程<代码>\u stop
将允许您优雅地停止线程。请注意,一旦停止线程
,就无法再次恢复。线程
不再可用
这段代码来自一个真实的开源项目:下面是一个简短的示例,介绍如何使用酷炫的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)之前暂停,则此操作将被阻止
您的类将如下所示:
private void Concurrent() {
if (shouldRun()) {
// notify threads to pause and wait for them
DoJob();
// resume threads
}
// Normal job...
}
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
}
}
你能给我举个简单的例子吗?谢谢。我注意到你正在自己创建线程。我不能那样做。我已经更新了我的问题。那么我怎么能做类似的事情呢?@AlirezaNoori我们能做这个吗?创建一个
守护进程线程
,然后让其他线程加入它?我想我对我的问题解释得不够好。请阅读第二次更新。我认为这会澄清问题。您是否考虑过改用阻塞队列
?线程只有通过向其添加代码来停止,才能停止。你不能在外部安全地停止/暂停线程。好的,这里有很多东西。你确定我的案子需要这些吗?请您阅读我的最新更新,并告诉我如何修改我的代码。在您的情况下,并发(…)与访问是一样的。关键(…)与单线程(…)相同。我不知道这个框架,但是如果你有一个以上的类实例,你可能需要把一个对象传递给所有的类,它们可以锁定。但让我来做点什么我用了你的密码。经过几次测试,效果良好。然而,当我在实际情况下测试时,似乎有一些错误。它就像:Crawler1->Probe Crawler2->Probe Crawler3->Probe…
你能帮帮忙吗?谢谢。你使用的是我修改过的类代码吗?您可能必须使SomeCriteria()方法线程安全。我认为您的一般问题是多个线程成为独占线程。您必须使此部件线程安全,并且不会出现死锁。基本上,你需要做的是创建一个“原子”块,在其中你获得了许可,一旦你获得了许可,就让其他人得不到许可。这可以通过AtomicBoolean和getAndSet(值)实现。这将检索是否允许您获得作为独占线程的权限,然后将其设置为false(因此它已被接受)。但是有了这一点,当你把它设置为真的时候,你必须关心比赛条件。