简单Java多线程测试不起作用

简单Java多线程测试不起作用,java,multithreading,Java,Multithreading,我编写了一些java代码,使用while循环在1秒内尽可能多地增加值 然后,我尝试在1秒内使用4个线程尽可能多地增加4个值。我希望有了四个线程,我得到的值是简单循环的四倍 代码如下: package threadTest; public class ThreadTestMain { public static void main(String[] args) { long end_time = 0; long value = 0; long runtime = 0;

我编写了一些java代码,使用while循环在1秒内尽可能多地增加值

然后,我尝试在1秒内使用4个线程尽可能多地增加4个值。我希望有了四个线程,我得到的值是简单循环的四倍

代码如下:

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();
}

}
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循环吗

有一个类比可以帮助理解我的问题:如果一个工人一天能挖一个洞,那么四个工人一天能挖四个洞


谢谢

看看你启动计时器的时间:你给每个单独的执行对象一秒钟的时间来尽可能多地计数,但是从什么时候开始算起一秒钟

第一个对象的1秒包括创建所有四个SeparateExecution对象所需的时间加上创建所有四个线程所需的时间,再加上它自己的线程启动所需的时间。最后一个对象的1秒包括创建一个单独的执行实例所需的时间,加上创建四个线程对象所需的时间,加上三个start()调用所需的时间,再加上它自己的线程启动时间。这是一个重大的障碍


编辑:这是我的版本。它使用一个本地计数器进行一次测量,使用一个实例变量计数器进行另一次测量,然后它启动线程(我的PC上有八个线程),同时执行实例变量测试。当我运行它时,前两次运行的计数大致相同,大约比并发运行产生的计数高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);
        }
    }
}
公共类线程{
公共静态void main(字符串[]args)引发InterruptedException{
多洛卡瓦尔();
doInMainThread();
多线程();
}
私有静态void doLocalVar(){
长计数=0L;
long startTime=System.currentTimeMillis();
长结束时间=开始时间;
而(结束时间-开始时间<1000L){
计数+=1L;
endTime=System.currentTimeMillis();
}
System.out.println(“local:appeased=“+(endTime-startTime)+”,count=“+count”);
}
私有静态void doInMainThread(){
微调器微调器=新微调器(“主”);
spinner.run();
spinner.show();
}
私有静态void doMultiThreaded()引发InterruptedException{
int numThreads=Runtime.getRuntime().availableProcessors();
线程[]线程=新线程[numThreads];
微调器[]微调器=新微调器[numThreads];

对于(inti=0;i,在我看来,不可能在所有线程中获得相同的数字

  • 您可能有4个进程,但并非所有四个进程都专用于java程序。它可能会将循环空间交换到其他进程(如操作系统进程、其他正在运行的进程…)

  • 我用没有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)

    公共类SimpleTask实现可运行{
    私有长值=0;
    私有易失性静态int-oneSecondCompleted=0;
    公共SimpleTask(长左值){
    this.value=左值;
    }
    @凌驾
    公开募捐{
    
    虽然(oneSecondCompleted您的结果的原因似乎很明显:
    System.currentTimeMillis
    在过程中的某个地方获得了一个锁,这使得代码基本上是连续的(内核调用是迄今为止在循环中完成的最昂贵的事情)

    在本例中,您希望四个线程的数量与顺序版本大致相同,这与实际情况基本相同

    有趣的问题是为什么
    System.currentTimeMillis
    需要一个锁?这是一个本机函数,在
    src/os//vm/os.cpp
    中实现,其中
    是linux、windows或solaris。稍微简化的函数在jdk9开发树中如下所示:

    jlong os::javaTimeMillis() {
        FILETIME wt;
        GetSystemTimeAsFileTime(&wt);
        return windows_to_java_time(wt);
    }
    
    因此Java本身不同步,因为
    GetSystemTimeAsFileTime
    是线程安全的。因此我们可以假设操作系统内部为该方法获取了锁-相当令人惊讶,我真的不明白为什么需要这样做。使用的结构只有8个字节,因此可以自动更新


    不管怎么说,如果在Linux上运行相同的代码不会出现这种行为,我也不会感到惊讶。

    可能系统时间内核只响应一个调用,并对其他调用进行排队。例如,如果它在某处有一个同步调用。由于其性能是限制因素,因此您正在测量可以执行的次数ll System.currenttime(),这在两种情况下大致相同。剩下的区别是上下文切换和维护线程的一般开销


    尝试在while循环中进行for检查,这样它只会每隔一千次左右检查一次时间条件。这应该足以使System.current time不再是限制因素。

    代码不会测试增量的性能。它测试
    System.currentTimeMillis()的性能
    ,这种方法伸缩性不好也就不足为奇了。@nosid,我不知道JVM,但知道System.currentTimeMillis()的实现可能非常便宜。但是,看看示例何时启动计时器:它会在创建线程之前启动计时器。事实上,第一个计时器是在创建所有SeparateExecution对象之前启动的。因此,线程化的情况是一个愚蠢的问题,但是您有多少个CPU内核?如果此代码在单个内核上运行,这就是exa正是您期望的结果。@SamDufel我运行的是双核i7,我认为它应该有4个线程。Intel core i7 M620 2.67Ghz处理器。@nosid System.currentTimeMillis()的使用在这两个线程中
    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;
        }
    }
    
    jlong os::javaTimeMillis() {
        FILETIME wt;
        GetSystemTimeAsFileTime(&wt);
        return windows_to_java_time(wt);
    }