Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:类完全在第二个线程/IllegalMonitorStateException中运行_Java_Multithreading_Concurrency - Fatal编程技术网

Java:类完全在第二个线程/IllegalMonitorStateException中运行

Java:类完全在第二个线程/IllegalMonitorStateException中运行,java,multithreading,concurrency,Java,Multithreading,Concurrency,当您希望某个任务由另一个线程执行时,可以扩展线程或实现Runnable 我试图创建一个完全在第二个线程中运行类的类 这意味着您可以调用立即返回并由第二个线程执行的任何方法 以下是我的尝试: import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQue

当您希望某个任务由另一个线程执行时,可以扩展线程或实现Runnable

我试图创建一个完全在第二个线程中运行类的类

这意味着您可以调用立即返回并由第二个线程执行的任何方法

以下是我的尝试:

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * Extend this class to run method calls asynchronously in the second thread implemented by this class.
 * Create method(type1 param1, type2 param2, ...) and let it call this.enqueueVoidCall("method", param1, param2, ...)
 * 
 * The thread executing the run-method will automatically call methodAsync with the specified parameters.
 * To obtain the return-value, pass an implementation of AsyncCallback to this.enqueueCall().
 * AsyncCallback.returnValue() will automatically be called upon completion of the methodAsync.
 *  
 */
public class ThreadedClass extends Thread {
    private static Object test;

    private Queue<String> queue_methods = new ConcurrentLinkedQueue<String>();
    private Queue<Object[]> queue_params = new ConcurrentLinkedQueue<Object[]>();
    private Queue<AsyncCallback<? extends Object>> queue_callback = new ConcurrentLinkedQueue<AsyncCallback<? extends Object>>();

    private volatile boolean shutdown = false;

/**
 *  The run method required by Runnable. It manages the asynchronous calls placed to this class.
 */
@Override
public final void run() {
    test = new Object();
    while (!shutdown) {
        if (!this.queue_methods.isEmpty()) {
            String crtMethod = queue_methods.poll();
            Object[] crtParamArr = queue_params.poll();
            String methodName = crtMethod + "Async";

            Method method;
            try {
                method = this.getClass().getMethod(methodName);
                try {
                    Object retVal = method.invoke(this, crtParamArr);
                    AsyncCallback<? extends Object> crtCallback = queue_callback.poll();
                    crtCallback.returnValue(retVal);
                } catch (Exception ex) {}
               } catch (SecurityException ex) {
               } catch (NoSuchMethodException ex) {}
        } else {
            try {
                synchronized(test ) {
                    test.wait();
                }
            } catch (InterruptedException ex) {
                System.out.println("READY");
            } catch (Exception ex) {
                System.out.println("READY, but " + ex.getMessage());
            }
        }
    }
}

/**
 * Asynchronously adds a method-call to the scheduler, specified by methodName with passed parameters 
 * @param methodName The name of the currently called method. methodName + "Async" is being called
 * @param parameters Parameters you may want to pass to the method
 */
protected final void enqueueVoidCall(String methodName, Object... parameters) {
    List<Object> tmpParam = new ArrayList<Object>();
    for (Object crt : parameters) {
        tmpParam.add(crt);
    }
    queue_methods.add(methodName);
    queue_params.add(parameters);
    queue_callback.add(null);
    test.notifyAll();
}

/**
 * Asynchronously adds a method-call to the scheduler, specified by methodName with passed parameters 
 * @param methodName The name of the currently called method. methodName + "Async" is being called
 * @param callBack An instance of AsyncCallback whose returnValue-method is called upon completion of the task.
 * @param parameters Parameters you may want to pass to the method
 */
protected final void enqueueCall(String methodName, AsyncCallback<? extends Object> callBack, Object... parameters) {
    List<Object> tmpParam = new ArrayList<Object>();
    for (Object crt : parameters) {
        tmpParam.add(crt);
    }
    queue_methods.add(methodName);
    queue_params.add(parameters);
    queue_callback.add(callBack);
    test.notifyAll();
}

/**
 * Complete the currently running task, optionally return values and eventually shut down. The instance of this object becomes unusable after this call. 
 */
public void shutdown() {
    shutdown=true;
}

}
以及开始工作的主要方法:

public class TestingClass {
public static void main(String[] args) {
    MySecondTask test = new MySecondTask();
    test.start();
    System.out.println("1. Thread [1]");
    // CORRECTION, SHOULD BE:
    test.test1();
    // INSTEAD OF:
    // test.test1Async();
    for(int q=0; q<=100000; q++) {
        System.out.println("1:"+ new Date().getTime()+":"+ q);
        if ((q % 1000) == 0) {
            System.out.flush();
        }
    }
    System.err.println("1. Thread [2]");
}

}
不知何故,第二个线程的输出总是首先完全显示,然后其他线程在控制台上输出。如果线程同时运行,这是预期的结果,那么控制台输出应该是混合的

任何想法,以及意见,以改善我的编码风格表示感谢

编辑:

所提到的问题已经完全解决了

现在,我在调用ThreadedClass.notifyAll的行上收到一个IllegalMonitorStateException

也许我把锁弄错了

但是a为什么需要使用synchronized around wait以及如何调用notifyAll来取消阻塞wait

提前感谢并致以最良好的问候


p、 s:你们在堆栈溢出方面都做得很好。你已经在不知不觉中帮了我很多次了,谢谢你。坚持下去

主线程等待test.test1Async返回,您在那里做什么?

Java线程在不同的机器上运行不同。有些机器先发制人,有些则不然。如果第二个线程在第一个线程之前输出其内容,那么运行代码的机器很可能是非抢占式的。如果您需要同步线程,有很多方法可以做到这一点,但是如果您不关心同步,那么就无法保证线程将如何运行

另外,test.test1Async在第一个线程中运行,而不是在第二个线程中运行。这可能是阻碍事态发展的原因

这意味着你可以打电话 立即返回的任何方法 由第二个执行 线

这听起来像是在与可赎回人、期货和执行人合作:

我不想告诉你,但你可能真的想调查一下这件事

编辑以解决下面的评论

只需使对象中的方法如下所示:

private ExecutorService executorService = Executors.newCachedThreadPool();

public Future<SomeObject> yourMethodName(String anyArguments) {
    return executorService.submit(
        new Callable<SomeObject>() {
            public SomeObject call() {
                SomeObject obj = new SomeObject();
                /* Your Code Here*/;
                return obj;
            }
        }
    );
}

风格建议:查看java.lang.reflect.Proxy和InvocationHandler。
您可以实现一个InvocationHandler来避免您正在处理的一些反射内容,用户可以直接调用真正的接口方法。

您正在同步调用test1Async。如果//bigjob在这里完成,那么它将不会与其他线程并行运行。您要做的是:

public class TestingClass {
public static void main(String[] args)
{
    MySecondTask test = new MySecondTask();
    test.start();
    System.out.println("1. Thread [1]");
    //test.test1Async();
    for(int q=0; q<=100000; q++)
    {
            System.out.println("1:"+ new Date().getTime()+":"+ q);
            if ((q % 1000) == 0)
            {
                    System.out.flush();
            }
    }
    System.err.println("1. Thread [2]");
}

}

记住,ThreadedClass.run方法将为您调用test1.testAsynch。事实上,我很惊讶你没有看到两次结果输出,或者计算混乱

您永远不会调用使用队列等的线程调度机制

我猜你是想打电话:

test.test1(); 
这反过来会将对test1Async的调用排入队列,但您错误地调用了:

test.test1Async();
直接在单个线程中执行整个过程

替换:

    ....
    System.out.println("1. Thread [1]");
    test.test1Async();
    for(int q=0; q<=100000; q++)
    {
    ...
与:

在编码方式上,在java编码时,使用与语句相同的开式括号,而C、C++和C中的JavaScript比你的方式更好。

也可以使用camelCase而不是带有下划线的separate_


这里有一个文档,详细介绍了。

我建议您完全按照Tim在回答中建议的方式实施它

您自己的想法虽然很有创意,但却打破了许多最佳实践,使您的代码非常脆弱。要记住的事情太多了,否则它会微妙地破裂

想一想那个人会在你之后使用、维护和扩展你的代码。想一想当你需要在一年内重温这段代码时会发生什么

只是列出了一些你不应该做的事情:

直接扩展线程被认为是不好的做法,更倾向于实现Runnable 避免将方法编码为文本-它将在第一次重构时中断 test1Async应该是私有的,否则团队的新成员会直接调用它 方法命名应该是明确的-*Async通常意味着在后台进行,而实际上是相反的方式 整体脆性——假设我需要更改test1以返回int而不是void——我真的会记得更改其他方法吗?你记得一年后再做吗?
TestingClass.main中是否有错误?我看不到它调用test1的地方。等等,你从哪里得到这个:AsyncCallback对象,它不是JavaOK的一部分。好的,我可以理解第一点。但是它不应该在第一个线程中运行,因为当前在run方法中的线程应该调用它,这是我的意图。为什么从第一个线程调用它?这有什么不对……好吧,什么操作系统能够读取StackOverflow并运行JV
M today不是抢占式多线程?@Atmocreations-当您告诉第二个线程启动时,它会在run方法中开始执行,但test.test1Async不会在run方法中调用,而是在主线程的main方法中调用。即使尝试不启动第二个线程,test1Async仍将运行。谢谢提示。我已经听说过这些设施,我想我知道这些设施的用途。我的问题是,我需要为我要调用的类的每个方法创建另一个Runnable实现。还是我弄错了?我只想能够调用myObject.method1,也许稍后调用myObject.method2。这些需要立即返回并异步执行后台工作。我想通过我尝试使用呼叫队列,这个任务可以完成。。。?!看看上面的新代码块。。这种类型的实现应该足以解决大多数问题。如果你想让它变得更可怕/复杂,你可以添加反射来为你添加可调用项和线程池提交,但我不推荐。谢谢。在我看来,这看起来比我做的更复杂。我同意蒂姆的观点,这是最好的方法,除非你想进入AOP。请参阅下面我的答案,了解为什么您的方法虽然在技术上是正确的,但并不可取。看起来既复杂又干净。也许我只是需要深入研究一下遗嘱执行人之类的事情。有人知道一个关于这些具体工作原理的好教程吗?我在javadoc中找到了一些关于类/接口的东西,但也许你可以推荐一些好的文档?哎哟,是的,你是对的。我刚刚发表的评论到哪里去了?当darthcoder评论这句话时,我发现有些事情不可能是对的。经过其他一些小的修改,我设法再次运行代码。但这一次,它在我调用notifyAll的行中抛出了非法的MonitorStateException。我知道,现在调用该方法的第二个线程不是锁所有者。但这就是notify的作用,对吗?以继续等待此操作的其他线程。你知道怎么纠正吗?感谢JDK引用:[IllegalMonitorStateException-如果当前线程不是此对象监视器的所有者。]问题是调用notifyAll的线程在测试时从不同步。如果不发布stacktrace,很难猜测,但我会猜测。在方法中:调用test.notifyAll的enqueueCall;为了使用notify,所有线程都必须拥有对象锁。顺便说一句,我对新的并发框架不太了解,但我很确定它应该用来解决通知/同步这类复杂问题。我知道如何使用裸锁/同步。如果你需要更多的帮助,现在就让我来。如果是这样的话,请考虑清理你的代码,把所有的打开括号放在一行,很难按照我的方式看他们的观点,THX。现在又有问题了。。。你可能想看看我对奥斯卡·雷耶斯·安瑟斯的评论,看看你的回答。好的,实现Runnable而不是扩展线程是我可以很容易接受的事情。。。将…异步设置为私有或受保护以实现可扩展性也是一个很好的观点。目前,我并不真正关心这一点,因为我只想让代码按预期运行;哦,我同意,也许是布列特。但是当我按照Tim建议的方式实现它时,我想我会再次遇到同样的问题,记住在更改代码时我必须做的不同更改。你有一个很好的积极态度,这很酷:关于Tim的解决方案,优点是它非常集中。例如,如果你想改变某个方法,你就去改变它,就是这样。无需转到其他方法,无需在某处更新某些文本字符串-只需找到该方法并修复它。现在这似乎不重要,但几个月后你会感谢我:
    ....
    System.out.println("1. Thread [1]");
    test.test1Async();
    for(int q=0; q<=100000; q++)
    {
    ...
   ....
    System.out.println("1. Thread [1]");
    test.test1();
    for ( int q=0; q<=100000 ; q++ ) {
    ....