Java多线程并发中部分不并发的问题

写Java实验发现个有意思的问题

三个线程,一个线程打印字符a,一个线程打印字符b,另一个线程打印数字,多次运行结果都是先打印混合输出的ab,完了再打印数字

Java多线程并发中部分不并发的问题_第1张图片

 有图有真相,我运行了10次

完整的代码是这个

class PrintChar implements Runnable{
    private char charToPrint;
    private int times;
    public PrintChar(char c,int t){
        charToPrint=c;
        times=t;
    }

    @Override
    public void run() {
        for(int i=0;i

字符a和字符b是混合输出的,这符合我们的预期,因为多线程是并发的,因此各个线程之间的输出顺序是不确定

但是我们却从中发现尽管字符a和b的顺序是不确定的,但是ab和数字的顺序却始终是先打印完ab再打印数字,这显然不科学,理论上数字也应该和ab一起混合输出,这究竟是为什么呢,我们观察到代码中,打印数字的线程是最后创建的,而且也是最后才启动的。

Java多线程并发中部分不并发的问题_第2张图片

会不会是因为这个呢,于是我们改为最先创建打印数字的线程,最先启动打印数字的线程。

Java多线程并发中部分不并发的问题_第3张图片

再次运行程序,很遗憾的发现,输出结果依然没有发生变化,数字依然在字母之后输出。

Java多线程并发中部分不并发的问题_第4张图片

于是我们把注意力放到了线程本身进行比较,发现同样是打印,但是打印字母的是直接打印一个固定的字符变量,而打印数字的则是打印一个字符串和整型变量相加的结果。

Java多线程并发中部分不并发的问题_第5张图片Java多线程并发中部分不并发的问题_第6张图片

我们把打印数字的换成一个固定的整形变量lastNum。

Java多线程并发中部分不并发的问题_第7张图片

再次运行程序10次,结果如下,这次看到了字母ab和数字混合出现的结果,可见原因就出现在我们刚刚替换的代码处。

Java多线程并发中部分不并发的问题_第8张图片

原本代码处是打印一个字符串和整型变量相加的结果,这里会隐形调用函数将整型变量转换为字符串,因此会比直接打印整型变量多一个函数调用的步骤,因此这里相比之下执行会更慢一些,而Java的线程调度是由操作系统内核来完成的,Java程序中的线程会被映射到操作系统的原生线程上,操作系统负责为这些线程分配CPU时间片,并根据调度策略来进行调度。那么在在默认情况下,Java线程的调度遵循抢占式的时间片轮转调度策略,每个线程都被分配一定的CPU时间片,当线程的时间片用完时,操作系统才会暂停该线程的执行,并将CPU时间片分配给其他等待执行的线程

所以这个CPU时间片足够让线程直接打印一个字符,但是不够让线程调用函数完成整型变量到字符串的转换以及相加的操作,因此在需要多个时间片完成打印数字的任务时,已经足够让打印字母的线程完成任务了。

为了验证我们的解释,我们将原本打印100个字母的线程任务换成了300个,让打印数字的线程有足够的CPU时间片在打印字母的线程还没完成任务的时候就打印出数字。

Java多线程并发中部分不并发的问题_第9张图片

再次运行程序10次,此时出现了数字和字母混合输出的现象,说明我们的分析是对的。

Java多线程并发中部分不并发的问题_第10张图片

你可能感兴趣的:(Java程序设计,java,开发语言)