【问题标题】:Threads not running at same time线程不同时运行
【发布时间】:2013-09-02 04:24:54
【问题描述】:

我创建了一个并发类来测试线程。因为我想找出同时运行线程的最佳方式。

我对我的结果感到惊讶:

test
test
Othertest
test
Othertest
test
test
test 

我预期的结果是线程随机返回,但它们似乎始终以相同的顺序返回!有谁知道为什么?这是否意味着它们没有同时运行?我怎样才能让它们同时运行?

这是我的代码:

public class ThreadTest {
    public static void main(String args[]) throws InterruptedException
    {
        new Thread(new ThreadTest().test()).start();
        new Thread(new ThreadTest().test()).start();
        new Thread(new ThreadTest().otherTest()).start();
        new Thread(new ThreadTest().test()).start();
        new Thread(new ThreadTest().otherTest()).start();
        new Thread(new ThreadTest().test()).start();
        new Thread(new ThreadTest().test()).start();
        new Thread(new ThreadTest().test()).start();
    }

    public  Runnable test() throws InterruptedException{
        Thread.sleep((long) (Math.random()*1000));
        System.out.println("test");
        return null;
    }

    public  Runnable otherTest() throws InterruptedException{
        Thread.sleep((long) (Math.random()*1000));
        System.out.println("Othertest");
        return null;
    }

}

【问题讨论】:

  • 他们实际上并没有在线程中运行任何东西。

标签: java multithreading concurrency threadpool


【解决方案1】:

Thread 构造函数接受RunnableThread 最终将在其上执行run() 方法。现在你没有返回 Runnable 对象。你正在返回null。因此,您在 test()otherTest() 方法中执行的操作是同步执行的。

您的所有执行都发生在一个线程中。这个

new Thread(new ThreadTest().test()).start();

执行test(),休眠一秒钟,打印"test"并返回nullstart() 调用没有任何作用,因为 Runnablenull。对于您所做的每个其他呼叫,这种情况都会继续。

您需要将 test()otherTest() 方法中的所有内容放在 Runnable#run() 方法中。例如

new Thread(new Runnable() {
    public void run() {
         Thread.sleep((long) (Math.random()*1000));
         System.out.println("test");
    }
}).start();

考虑Thread类的run()方法的源码,在调用start()时执行

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

其中target 是您在构造函数中传递的Runnable 引用。显然,如果是null,它什么也做不了。

【讨论】:

  • 谢谢你,这确实很好地解释了正在发生的事情
【解决方案2】:

我认为您可能会因此获得更好的运气:

public class ThreadTest {
public static void main(String args[]) throws InterruptedException
{
    new Thread(test).start();
    new Thread(test).start();
    new Thread(otherTest).start();
    new Thread(test).start();
    new Thread(otherTest).start();
    new Thread(test).start();
    new Thread(test).start();
    new Thread(test).start();
}

public static Runnable test = new Runnable() {
    @Override
    public void run()  {
        try {
            Thread.sleep((long) (Math.random()*1000));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("test");
    }
};

public static Runnable otherTest = new Runnable() {
    @Override
    public void run(){
        try {
            Thread.sleep((long) (Math.random()*1000));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Othertest");
    }
};

}

这个想法是将Runnable 的实例作为参数传递给Thread 构造函数。你并没有真正这样做,因为test()otherTest() 都返回null。上面的代码显示了一种以我猜你想要的方式运行线程的方法。其他方法当然是可能的。

【讨论】:

  • Runnables 不允许抛出InterruptedException。实际上,您必须捕获这些异常并在发生这种情况时中断当前线程。
  • 谢谢,我正要对此发表评论,所以我编辑了他的评论
  • @ChrisJester-Young - 哎呀。你是对的。我看到 kevinn205 继续并纠正了它。
  • 这个例子我认为不会是线程安全的,除非我抛出一个同步或返回初始化一个新的线程测试,是否正确?
  • @kevinn205 - 只要你有多个线程在没有同步的情况下调用System.out.println,就有可能出现乱码输出。 (尽管您通常可以侥幸逃脱。例如,参见this discussion thread。)创建ThreadTest 的实例对此无济于事;你需要同步。我不知道你说的“除非我扔了一个同步”是什么意思。
【解决方案3】:

您需要将testotherTest 方法实现为Runnable 实现。像这样:

private static class Test implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep((long) (Math.random()*1000));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return;
        }
        System.out.println("test");
    }
}

private static class OtherTest implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep((long) (Math.random()*1000));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return;
        }
        System.out.println("Othertest");
    }
}

public static void main(String args[]) {
    new Thread(new Test()).start();
    new Thread(new Test()).start();
    new Thread(new OtherTest()).start();
    new Thread(new Test()).start();
    new Thread(new OtherTest()).start();
    new Thread(new Test()).start();
    new Thread(new Test()).start();
    new Thread(new Test()).start();
}

当然,您可以尝试减少一点重复:

private enum Runnables implements Runnable {
    TEST {
        @Override
        public void run() {
            if (!sleep()) return;
            System.out.println("test");
        }
    },
    OTHER_TEST {
        @Override
        public void run() {
            if (!sleep()) return;
            System.out.println("Othertest");
        }
    };

    static boolean sleep() {
        try {
            Thread.sleep((long) (Math.random()*1000));
            return true;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }
}

public static void main(String args[]) {
    new Thread(Runnables.TEST).start();
    new Thread(Runnables.TEST).start();
    new Thread(Runnables.OTHER_TEST).start();
    new Thread(Runnables.TEST).start();
    new Thread(Runnables.OTHER_TEST).start();
    new Thread(Runnables.TEST).start();
    new Thread(Runnables.TEST).start();
    new Thread(Runnables.TEST).start();
}

【讨论】:

  • 感谢您的详细回复,有趣的是,您似乎可以将几个可运行对象包装到一个可运行对象枚举中,并且由于您使用工具调用它们,因此当您使用 Runnables.test 访问它们时,它会成为可运行对象
【解决方案4】:

您的Thread 实现是错误

您应该实现 Runnable 并实现 run() 方法或 您应该扩展 Thread 类并覆盖 run() 方法。

正在发生的事情是您的 test() 方法或 otherTest() 正在被调用,就像任何方法调用一样。而且由于您没有任何 run() 方法,因此您的 Thread.start() 不会简单地运行任何东西。

尝试改变你的方法,如下所示。

public Runnable test() {
    return new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep((long) (Math.random() * 1000));
                System.out.println("test");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
}


public Runnable otherTest() {
    System.out.println("Othertest");
    return new Runnable() {

        @Override
        public void run() {
            try {
                Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("Othertest");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
}

【讨论】:

  • 谢谢,你的意思是“new Thread(new ThreadTest().test()).start();”吗?应该怎么做?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-24
  • 2013-08-13
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 2010-10-20
相关资源
最近更新 更多