我写了一些java代码,使用while循环可以在1秒内增加一个值。
然后我尝试使用4个线程在1秒内尽可能多地增加四个值。我期待有四个线程,与简单的循环相比,我将得到四倍的值。
代码如下:
package threadTest;
public class ThreadTestMain {
public static void main(String[] args) {
long end_time = 0;
long value = 0;
long runtime = 0;
long start_time = System.currentTimeMillis();
while (runtime<=1000) {
value++;
runtime = System.currentTimeMillis() - start_time;
}
System.out.println(value);
end_time = System.currentTimeMillis();
System.out.println("DEBUG-> Time should be 1sec : " + (end_time - start_time));
SeperateExecution myObject = new SeperateExecution(0);
SeperateExecution myObject2 = new SeperateExecution(0);
SeperateExecution myObject3 = new SeperateExecution(0);
SeperateExecution myObject4 = new SeperateExecution(0);
Thread worker1 = new Thread(myObject,"worker1");
Thread worker2 = new Thread(myObject2,"worker2");
Thread worker3 = new Thread(myObject3,"worker3");
Thread worker4 = new Thread(myObject4,"worker4");
worker1.start();worker2.start();worker3.start();worker4.start();
}
}
和
package threadTest;
//import java.util.concurrent.atomic.AtomicLong;
public class SeperateExecution implements Runnable {
private long value = 0;
//private AtomicLong value = null;
private long start_time = 0;
public SeperateExecution (long p_val)
{
this.value = p_val;
//this.value = new AtomicLong(p_val);
//this.start_time = p_st;
}
@Override
public void run(){
long runtime = 0;
this.start_time = System.currentTimeMillis();
while (runtime<=1000) {
//value.incrementAndGet();
value++;
runtime = System.currentTimeMillis() - start_time;
}
System.out.println(Thread.currentThread().getName() + " DONE " + value +
" Thread Exection Time " + (System.currentTimeMillis()- start_time));
}
}
代码输出如下:
52266551
DEBUG-> Time should be 1sec : 1001
worker1 DONE 13364059 Thread Exection Time 1001
worker2 DONE 13744972 Thread Exection Time 1001
worker4 DONE 11652084 Thread Exection Time 1001
worker3 DONE 13605645 Thread Exection Time 1001
有人可以帮助我理解为什么多线程值总和一个小于正常while循环的值吗?
一个类比,以帮助理解我的问题:如果一个工人一天可以挖一个洞,那么四个工人一天可以挖四个洞。
由于
答案 0 :(得分:3)
你的结果的原因似乎相当明显:System.currentTimeMillis
在某个地方获得一个锁定,这使得代码基本上是顺序的(内核调用是迄今为止最昂贵的事情。环)。
在这种情况下,您希望四个线程的数量与顺序版本大致相同,这几乎就是发生的事情。
有趣的问题是为什么System.currentTimeMillis
需要锁定?它是src/os/<os>/vm/os_<os>.cpp
中实现的本机函数,其中<os>
是linux,windows或solaris。稍微简化的函数在jdk9开发树中看起来如下:
jlong os::javaTimeMillis() {
FILETIME wt;
GetSystemTimeAsFileTime(&wt);
return windows_to_java_time(wt);
}
因此,GetSystemTimeAsFileTime
是线程安全的,因此Java本身不会同步。所以我们可以假设操作系统内部获取了该方法的锁定 - 相当令人惊讶,我真的不明白为什么这是必要的...使用的结构只有8个字节,因此可以原子更新。 / p>
无论如何,如果在Linux上运行相同的代码并不会表现出这样的行为,我不会感到惊讶。
答案 1 :(得分:1)
在我看来,不可能在所有线程中获得相同的数字。
你可能有4个处理器,但没有必要全部四个专用于你的java程序。它可以将循环空间交换到其他进程(如OS进程,其他进程正在运行..)
我在没有System.currentMill
结果如下
Thread3 Value :413907923
Thread1 Value :431271274
Thread2 Value :426025618
Thread4 Value :431386076
我尝试了8个线程(我有4个核心)这里是结果
Thread7 Value :441240435
Thread4 Value :283265150
Thread2 Value :427759029
Thread3 Value :441240435
Thread8 Value :283265150
Thread6 Value :427759029
Thread5 Value :450884067
Thread1 Value :450884067
(它甚至没有按顺序执行SOP)
public class SimpleTask implements Runnable {
private long value = 0;
private volatile static int oneSecondCompleted = 0;
public SimpleTask(long lValue) {
this.value = lValue;
}
@Override
public void run() {
while(oneSecondCompleted <= 1){
if (oneSecondCompleted == 1){
while (oneSecondCompleted == 1){
this.value++;
}
}
}
System.out.println(Thread.currentThread().getName() +" Value :"+value);
}
public static void main(String args[]){
SimpleTask task1 = new SimpleTask(0);
SimpleTask task2 = new SimpleTask(0);
SimpleTask task3 = new SimpleTask(0);
SimpleTask task4 = new SimpleTask(0);
Thread thread1 = new Thread(task1,"Thread1");
Thread thread2 = new Thread(task2,"Thread2");
Thread thread3 = new Thread(task3,"Thread3");
Thread thread4 = new Thread(task4,"Thread4");
thread1.start();thread2.start();thread3.start();thread4.start();
oneSecondCompleted = 1;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
oneSecondCompleted = 2;
}
}
答案 2 :(得分:0)
看看你何时启动你的计时器:你给每个SeparateExecution对象一秒钟的数量尽可能高,但从一开始就是一秒?
您的第一个对象的一秒包括创建所有四个SeparateExecution对象所需的时间加上创建所有四个线程所需的时间,加上其自己的线程启动所需的时间。你的最后一个对象的一秒包括创建一个SeparateExecution实例所需的时间,加上创建四个线程对象所需的时间,加上三次start()调用所花费的时间,加上它自己的线程启动时间。这是一个重大障碍。
编辑:这是我的版本。它使用本地计数器进行一次测量,使用实例变量计数器执行另一次测量,然后启动线程(我的PC上有8个线程)同时执行instance-var测试。当我运行它时,前两个运行计数大致相同,大约是并发运行产生的计数的1.5倍。
public class Threadly {
public static void main(String[] args) throws InterruptedException {
doLocalVar();
doInMainThread();
doMultiThreaded();
}
private static void doLocalVar() {
long count = 0L;
long startTime = System.currentTimeMillis();
long endTime = startTime;
while (endTime - startTime < 1000L) {
count += 1L;
endTime = System.currentTimeMillis();
}
System.out.println("local: elapsed=" + (endTime - startTime) + ", count=" + count);
}
private static void doInMainThread() {
Spinner spinner = new Spinner("main");
spinner.run();
spinner.show();
}
private static void doMultiThreaded() throws InterruptedException {
int numThreads = Runtime.getRuntime().availableProcessors();
Thread[] threads = new Thread[numThreads];
Spinner[] spinners = new Spinner[numThreads];
for (int i=0 ; i<numThreads ; i++) {
spinners[i] = new Spinner("t-" + Integer.toString(i));
threads[i] = new Thread(spinners[i]);
}
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
for (Spinner spinner : spinners)
spinner.show();
}
private static class Spinner implements Runnable {
private long startTime;
private long endTime;
private long count;
private final String name;
Spinner(String name) {
this.name = name;
}
// @Override
public void run() {
count = 0L;
startTime = System.currentTimeMillis();
endTime = startTime;
while (endTime - startTime < 1000L) {
count += 1L;
endTime = System.currentTimeMillis();
}
}
void show() {
System.out.println(name + ": elapsed=" + (endTime - startTime) + ", count=" + count);
}
}
}
答案 3 :(得分:0)
系统时间的内核可能只响应一个呼叫并将其他呼叫排队。例如。如果它在某处有同步呼叫。由于它的性能是限制因素,因此您要测量可以调用System.currenttime()的次数,这两种情况大致相同。剩下的差异归结为上下文切换和维护线程的一般开销。
尝试在while循环中进行查看,因此它只会在每增加一千次左右时检查一次时间条件。这应该足以使System.current时间不再是限制因素。