从另一个线程调用方法时,主线程被阻塞

时间:2018-04-25 14:29:40

标签: java multithreading

我正在尝试使用自定义对象创建一个新线程,然后从主线程调用此自定义对象方法。这个想法是主线程可以继续做其他事情,而自定义对象继续在第二个线程中工作:

public class Multithreading {
    public static void main(String[] args) {

        Multithreading mt = new Multithreading();
        mt.multiTest();
    }

    public void multiTest() {
        SomeObject someObject = new SomeObject();
        Thread thread = new Thread(someObject);
        thread.setDaemon(true);
        thread.start();
        someObject.startit();
        int i = 0;
        while (i < 3) { 
            try {

                System.out.println("this is the main thread being busy");

                Thread.sleep(3000);
                i += 1;
            } catch (InterruptedException e) {
            }

        }
    }

    class SomeObject implements Runnable {

        public void sayHello() {
            System.out.println("this is the second thread being busy");
        }

        public void startit() {
            int i = 0;
            while (i < 3) {
                try {
                    sayHello();

                    Thread.sleep(3000);
                    i += 1;
                } catch (InterruptedException e) {
                }
            }

        }

        @Override
        public void run() {
            // TODO Auto-generated method stub

        }
    }
}

输出结果为:

this is the second thread being busy
this is the second thread being busy
this is the second thread being busy
this is the main thread being busy
this is the main thread being busy
this is the main thread being busy

应该更像这样:

this is the second thread being busy
this is the main thread being busy
this is the second thread being busy
this is the main thread being busy
this is the second thread being busy
this is the main thread being busy

因此主线程被阻塞,直到方法完成。主线程是否等待第二个线程中的someObject.startit()完成(作为返回类型为void,我认为情况不是这样)?或者它是在第一个线程中执行,因此阻止了它?

我知道使用以下代码我可以在另一个线程中执行someObject.startit(),但每次都会从头开始创建,我无法承担线程创建开销:

new Thread(() -> {someObject.startit();}).start(); 

一个线程如何在不阻塞的情况下从另一个线程中的对象调用方法?

5 个答案:

答案 0 :(得分:2)

在另一个中执行的是Runnable对象的run方法。在您的情况下,run方法为空,因此在另一个线程中没有任何操作。然后你从主线程调用startit(),所以它在主线程中执行。这就是你得到这个结果的原因。

尝试将startit()的正文放在run

答案 1 :(得分:2)

  

主线程是否正在等待someObject.startit()的完成   第二个线程(作为返回类型的void,我会认为这个   不会是这样的)?或者它是在第一个线程中执行的,   因此阻止它?

直接在someObject.startit()中调用multiTest时,它会在第一个调用线程中执行。

了解 Runnbale不是Thread 非常重要,Runnbale只是普通对象,除了run方法将是当您使用它创建并启动新的Thread时执行,如下所示:

new Thread(new Runnable()).start;

所以,实际上,在这种情况下,与线程阻塞没有任何关系。您可以将startit()移动到run方法,因此它将由第二个线程执行:

@Override
public void run() {
    startit();
}

并且,为了避免线程创建开销,您可以使用线程池来执行它:

ExecutorService executorService = Executors.newCachedThreadPool(); // It should a singlton
// ExecutorService executorService = Executors.newFixedThreadPool(threadSize);
executorService.execute(() -> {
    someObject.startit();
});

答案 2 :(得分:0)

someObject.startit();按顺序运行,而不是在您创建的线程上运行。

要使其正常工作,您需要在startit();类的run()方法中调用SomeObject方法

答案 3 :(得分:0)

你应该在run方法中调用你的函数,因为它是实际实现多线程的方法。

答案 4 :(得分:0)

如果我理解正确你想要创建一个新线程,然后命令该线程进行一些计算,而不是每次都创建一个新线程。

我建议您使用ExecutorService class。它可用于管理一组线程,这些线程将接受新的并发工作,而不会在每次调用方法时创建新线程的开销。

使用以下方式初始化服务:

 ExecutorService pool = Executors.newFixedThreadPool(poolSize);

然后在池调用pool.execute(Runnable)中的一个线程中运行一个方法。在此示例中,我将在startit上使用您的someobject方法。如果池中有可用的线程,它将在该线程中运行,否则它将被放入队列以等待线程变为可用。

 pool.execute(someObject::startit);