Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/388.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 线程如何共享创建它们的同一实例的字段变量?_Java_Multithreading_Runnable - Fatal编程技术网

Java 线程如何共享创建它们的同一实例的字段变量?

Java 线程如何共享创建它们的同一实例的字段变量?,java,multithreading,runnable,Java,Multithreading,Runnable,我想测试接口是否可运行。 创建实现可运行接口的类的实例。然后通过同一实例创建三个线程。观察线程如何共享实例的字段变量。 两个问题: 1.为什么这两个结果不像“20,19,18…1,0”的顺序? 2.为什么这两个结果彼此不同?(我运行代码两次。) 代码如下: public class ThreadDemo2 { public static void main(String[] args) { // TODO Auto-generated method stub

我想测试接口是否可运行。 创建实现可运行接口的类的实例。然后通过同一实例创建三个线程。观察线程如何共享实例的字段变量。 两个问题: 1.为什么这两个结果不像“20,19,18…1,0”的顺序? 2.为什么这两个结果彼此不同?(我运行代码两次。) 代码如下:

public class ThreadDemo2 {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TestThread tt = new TestThread();
        Thread t1 = new Thread(tt);
        Thread t2 = new Thread(tt);
        Thread t3 = new Thread(tt);
        t1.start();
        t2.start();
        t3.start();
    }
}
class TestThread implements Runnable {
    public int tickets = 20;
    public void run(){
        while (tickets >= 0){
            System.out.println(Thread.currentThread().getName() + ":the number of tickets is " + tickets--);
        }
    }
}
我运行了两次代码。这两个结果如下所示。 第一次:

Thread-1:the number of tickets is 20
Thread-2:the number of tickets is 18
Thread-2:the number of tickets is 16
Thread-0:the number of tickets is 19
Thread-2:the number of tickets is 15
Thread-1:the number of tickets is 17
Thread-2:the number of tickets is 13
Thread-0:the number of tickets is 14
Thread-2:the number of tickets is 11
Thread-1:the number of tickets is 12
Thread-2:the number of tickets is 9
Thread-0:the number of tickets is 10
Thread-2:the number of tickets is 7
Thread-1:the number of tickets is 8
Thread-2:the number of tickets is 5
Thread-0:the number of tickets is 6
Thread-2:the number of tickets is 3
Thread-1:the number of tickets is 4
Thread-2:the number of tickets is 1
Thread-0:the number of tickets is 2
Thread-1:the number of tickets is 0
Thread-0:the number of tickets is 19
Thread-2:the number of tickets is 18
Thread-2:the number of tickets is 16
Thread-2:the number of tickets is 15
Thread-1:the number of tickets is 20
Thread-2:the number of tickets is 14
Thread-2:the number of tickets is 12
Thread-2:the number of tickets is 11
Thread-0:the number of tickets is 17
Thread-2:the number of tickets is 10
Thread-2:the number of tickets is 8
Thread-1:the number of tickets is 13
Thread-1:the number of tickets is 6
Thread-1:the number of tickets is 5
Thread-2:the number of tickets is 7
Thread-0:the number of tickets is 9
Thread-2:the number of tickets is 3
Thread-1:the number of tickets is 4
Thread-2:the number of tickets is 1
Thread-0:the number of tickets is 2
Thread-1:the number of tickets is 0
第二次:

Thread-1:the number of tickets is 20
Thread-2:the number of tickets is 18
Thread-2:the number of tickets is 16
Thread-0:the number of tickets is 19
Thread-2:the number of tickets is 15
Thread-1:the number of tickets is 17
Thread-2:the number of tickets is 13
Thread-0:the number of tickets is 14
Thread-2:the number of tickets is 11
Thread-1:the number of tickets is 12
Thread-2:the number of tickets is 9
Thread-0:the number of tickets is 10
Thread-2:the number of tickets is 7
Thread-1:the number of tickets is 8
Thread-2:the number of tickets is 5
Thread-0:the number of tickets is 6
Thread-2:the number of tickets is 3
Thread-1:the number of tickets is 4
Thread-2:the number of tickets is 1
Thread-0:the number of tickets is 2
Thread-1:the number of tickets is 0
Thread-0:the number of tickets is 19
Thread-2:the number of tickets is 18
Thread-2:the number of tickets is 16
Thread-2:the number of tickets is 15
Thread-1:the number of tickets is 20
Thread-2:the number of tickets is 14
Thread-2:the number of tickets is 12
Thread-2:the number of tickets is 11
Thread-0:the number of tickets is 17
Thread-2:the number of tickets is 10
Thread-2:the number of tickets is 8
Thread-1:the number of tickets is 13
Thread-1:the number of tickets is 6
Thread-1:the number of tickets is 5
Thread-2:the number of tickets is 7
Thread-0:the number of tickets is 9
Thread-2:the number of tickets is 3
Thread-1:the number of tickets is 4
Thread-2:the number of tickets is 1
Thread-0:the number of tickets is 2
Thread-1:the number of tickets is 0

这是多线程程序的正常行为。instatnt上只能有有限数量的线程获得CPU,具体取决于处理器的容量。在多线程环境中,每个线程都有cpu时间,这个顺序可能是连续的,也可能不是连续的

您可以使用“synchronized”语句进行顺序处理。虽然此程序用于显示多线程的强大功能,而使用同步会扼杀实际用途,但在某些情况下需要同步,例如访问共享资源

以下是赫伯特·席尔德的完整参考资料中的几行

Java被设计为在广泛的环境中工作。一些 这些环境中的大多数实现多任务的方式与其他环境根本不同。对于 安全性方面,共享相同优先级的线程应该偶尔产生一次控制。这 确保所有线程都有机会在非强制操作系统下运行。 实际上,即使在非抢占性环境中,大多数线程仍然有机会运行, 因为大多数线程不可避免地会遇到一些阻塞情况,比如等待 I/O。发生这种情况时,阻塞的线程被挂起,其他线程可以运行。但是 如果您想要平滑的多线程执行,最好不要依赖它。也, 某些类型的任务是CPU密集型的。这样的线程控制着CPU

一个线程可以有五种状态。
当一个线程正在运行时,所有其他线程都在争夺CPU。任何线程(根据优先级)都可以获得CPU。因此,顺序不一定是连续的。这就是为什么每次运行都会得到随机输出。

这就是多线程。线程分别调度到处理器上,甚至可以在不同的CPU核上以真正的并行方式运行(如果您有多核处理器)。 这就是为什么这两次运行会产生不同的结果:线程调度的方式取决于当前环境,而当前环境还包括系统中的其他进程

线程执行可能以各种方式交错,来自不同线程的
println
到达单个输出日志的顺序也可能不同。一个线程可能已递减计数器,但在写入输出日志之前,其他线程可能同时执行了其他操作。在第一个线程有机会写入较旧的值之前,其他线程甚至可能已经递减并写入了较新的值。这些都是可能的和有效的交错,这就是为什么您可能无法在输出中获得递减顺序


见鬼,如果您使用更多线程进行更多测试,您甚至可能会看到相同的值从两个不同的线程弹出两次!这是因为两个线程可能同时尝试读取或写入
tickets
字段,导致它们都读取相同的值。存在各种有趣的并发问题,这就是为什么需要同步机制(如锁、信号量或原子更新)来获得正确的行为。

欢迎来到令人惊叹的并行处理世界。在使用线程时,除非您使用诸如锁和屏障之类的同步机制,否则没有人能够保证如何安排线程的进度

这里您要做的是打印一个统一的输出流,应该显示线程的进展情况。这意味着您正在合并来自线程的打印输出,但您无法判断这些打印是如何交叉的。此外,打印不一定按照调用函数的顺序进行,有几层缓冲,更糟糕的是,对打印代码的实际调用不是通过读取和减量自动完成的

您可以说变量被重复递减(尽管由于它没有使用任何原子/同步机制,您甚至不能确定不会看到重复的结果和递减被覆盖),并且每个线程在打印较低的值之后不会打印较高的值,而是在线程之间,这些消息可能会被暂停,从而导致打印顺序错误

当您在第一个示例中看到-

Thread-2:the number of tickets is 16
Thread-0:the number of tickets is 19
线程0实际上首先读取并递减变量,但打印延迟(由于上下文切换或其他原因)。线程2在其他几个实例之后运行,但立即打印了它的消息,只有到那时线程0才能完成之前的实例。
请注意,这里没有看到线程0在打印中间的任何其他值,它的下一次迭代已经读取14

编辑: 为了进一步阐述,这里有一个可能的交错的小例子

假设每个线程的机器代码是-(以虚构的伪格式)

(var是一个内存位置,位于堆栈上,例如)

假设有两个线程在运行。一种可能的交织可以是——

thread 0              |   thread 1
------------------------------------
load [var] -> rax     |                          // reads 20
dec rax               |
store rax -> [var]    |
                      |  load [var] -> rax       // reads 19
                      |  dec rax         
                      |  store rax -> [var]
                      |  call print function     // prints 19
                      |  cmp rax, 0           
                      |  jg label 
call print function   |                          //prints 20
cmp rax, 0            |
jg label              |
这有点过于简单化,但它显示了如何将值按顺序打印出来。只要在同一线程内保持顺序,任何交织都是可能的

还要注意的是,您可以有

thread 0              |   thread 1
------------------------------------
load [var] -> rax     |                          // reads 20
dec rax               |
                      |  load [var] -> rax       // reads 20 again !!!
                      |  dec rax         
                      |  store rax -> [var]
store rax -> [var]    |
...

在这种情况下,您将得到20个打印两次。

因此您有三个线程,所有线程都处理一个变量。我想这是有意的

这是