我有一个四核CPU。我创建4个线程并运行一个cpu密集循环,它需要>比在一个线程中以程序方式运行它长4倍。
我创建了两个要比较的项目,一个是线程,另一个没有。我将展示代码和运行时间。请注意没有线程的项目看起来很奇怪的原因是我想复制内存开销,因为我不确定它会影响运行时间。所以,这是没有线程的代码:
class TimeTest implements Runnable {
private Thread t;
private String name;
TimeTest(String name) {
this.name = name;
System.out.println("Creating class " + name);
}
public void run() {
System.out.println("Running class " + name);
int value = 100000000;
// try {
while (--value > 0) {
Math.random();
// Thread.sleep(1);
// System.out.println("Class " + name + " " + value);
}
// } catch (InterruptedException e) {
// System.out.println("Interrupted " + name);
// }
System.out.println("Class " + name + " exiting...");
}
public void start() {
System.out.println("Starting class " + name);
if (t == null) {
t = new Thread(this, name);
// t.start();
this.run();
}
}
}
public class ThreadComp {
public static void main(String[] args) {
TimeTest one = new TimeTest("Class-1");
one.start();
TimeTest two = new TimeTest("Class-2");
two.start();
TimeTest three = new TimeTest("Class-3");
three.start();
TimeTest four = new TimeTest("Class-4");
four.start();
}
}
大约需要11秒钟。
以下是带线程的代码:
class RunnableTest implements Runnable {
private Thread t;
private String name;
RunnableTest(String name) {
this.name = name;
System.out.println("Creating thread " + name);
}
public void run() {
System.out.println("Running thread " + name);
int value = 100000000;
// try {
while (--value > 0) {
Math.random();
// Thread.sleep(1);
// System.out.println("Thread " + name + " " + value);
}
// } catch (InterruptedException e) {
// System.out.println("Interrupted " + name);
// }
System.out.println("Thread " + name + " exiting...");
}
public void start() {
System.out.println("Starting thread " + name);
if (t == null) {
t = new Thread(this, name);
t.start();
}
}
}
public class ThreadTest {
public static void main(String[] args) {
RunnableTest one = new RunnableTest("Thread-1");
one.start();
RunnableTest two = new RunnableTest("Thread-2");
two.start();
RunnableTest three = new RunnableTest("Thread-3");
three.start();
RunnableTest four = new RunnableTest("Thread-4");
four.start();
}
}
大约需要1分13秒。
现在,在我正在学习的例子中,他们在领导期间调用Thread.sleep达50ms。如果我这样做,线程运行得更快如果我也在非线程类上调用Thread.sleep(50)。
哪个好,我知道如何让它发挥作用。但是我学习这个的原因是我正在寻找路径,而且我不打算在已经需要很长时间的事情上添加一个Sleep调用,并且不需要暂停甚至不执行1ms(除非它绝对必须)。
所以,我想知道的是我错过了什么?线程绝对必须要进入休眠状态,或者对象是否必须等待才能使它们按照我的意图工作(即并行运行所有四个循环)?
即使我只是犯了一个错误,为什么这会花费更长时间?我认为最糟糕的情况是,它仍会在11秒内完成,它会以一些不可预见的顺序完成....
答案 0 :(得分:11)
执行时间的巨大差异是由Math.random()
方法引起的。如果您将深入了解它的实现,您将看到它使用在所有线程之间共享的静态randomNumberGenerator
。如果你更进一步,那么你会注意到执行依赖于int next(int)
方法,而Random.seed
方法又使用AtomicLong
,Random
(考虑所有线程使用AtomicLong
的相同实例{1}}!)。现在我们来 SELECT a.id, a.name, a.address, a.etc,
c.Name
FROM Clients a
JOIN CoursesForClients b USING(ClientID)
JOIN Courses c USING(CourseID)
ORDER BY a.id, c.CourseID
,这是通过optimistic locking实现的 - 这就是问题所在。乐观锁不是为高负载而设计的,当多个线程试图同时访问它们时,它们会受到很大的影响,这就是你所观察到的性能下降。
TL; DR:使用ThreadLocalRandom(感谢@ bayou.io提及此内容)并享受性能提升。
答案 1 :(得分:1)
您的问题是您正在使用Math.random()
。关于这种方法的文档:
...
此方法 已正确同步 ,以允许多个线程正确使用。 但是,如果许多线程需要以很高的速率生成伪随机数,则可以减少每个线程拥有自己的伪随机数生成器的争用。
(强调我的)
因此,解决方案是为每个线程创建一个新的Random
。