Rya*_*yan 3 java multithreading runnable
我想测试Runnable接口.创建实现接口Runnable的类的实例.然后由同一个实例创建三个线程.观察线程如何共享实例的字段变量. 两个问题: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--);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我运行代码两次.两个结果如下所示. 第一次:
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
Run Code Online (Sandbox Code Playgroud)
第二次:
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
Run Code Online (Sandbox Code Playgroud)
这是多线程程序的正常行为。只有有限数量的线程才能使CPU处于不变状态,具体取决于处理器的容量。在多线程环境中,每个线程都会获得cpu时间,并且此顺序可能是连续的,也可能不是连续的。
您可以使用'synchronized`语句进行顺序处理。尽管此程序用于显示多线程的功能,并且使用同步杀死了实际目的,但在某些情况下需要进行同步,例如访问共享资源。
这是赫伯特·希尔德(Herbert schildt)完整引用的几行内容
Java旨在在广泛的环境中工作。这些环境中的某些环境与其他环境在根本上不同。为了安全起见,共享相同优先级的线程应偶尔产生控制权。这样可以确保所有线程都有机会在非抢先式操作系统下运行。实际上,即使在非抢占式环境中,大多数线程仍然有运行的机会,因为大多数线程不可避免地会遇到某些阻塞情况,例如等待I / O。发生这种情况时,被阻塞的线程将挂起,其他线程可以运行。但是,如果您想要平滑的多线程执行,最好不要依赖于此。另外,某些类型的任务会占用大量CPU。这样的线程控制着CPU。
线程可以有五个状态。
当线程正在运行时,所有其他线程都在争夺CPU。任何线程(根据它们的优先级)都可以获取CPU。因此,该顺序可能不一定是连续的。这就是为什么每次运行都会随机输出的原因。
欢迎来到令人惊叹的并行处理世界.使用线程时,除非您使用锁和障碍等同步机制,否则任何人都无法保证如何安排进度.
你在这里要做的是打印一个统一的输出流,据说可以显示线程的进展情况.这意味着您正在合并线程中的打印输出,但您无法分辨这些打印是如何交错的.此外,打印不一定按调用函数的顺序完成,有几层缓冲,更糟糕的是 - 对打印代码的实际调用不是通过读取和减量原子完成的.
你可以说变量是重复递减的(虽然因为它没有使用任何原子/同步机制你甚至不能确定你不会看到重复的结果和减少被覆盖),并且每个线程都不会打印更高的在打印较低值之后的值,但在线程之间,消息可能会停止,因此打印失序.
当你在第一个例子中看到 -
Thread-2:the number of tickets is 16
Thread-0:the number of tickets is 19
Run Code Online (Sandbox Code Playgroud)
线程0实际上首先读取和递减变量,但打印延迟(由于上下文切换或其他任何原因).线程2在其他一些实例已经完成之后运行,但是立即打印它的消息,然后线程0才完成那个早期的实例.
请注意,您在此处看不到线程0在其间打印任何其他值,其下一次迭代已经读取14.
编辑: 进一步详细说明,这是一个可能的交错的小例子.
假设每个线程的机器代码是 - (以伪格式编写)
label:
load [var] -> rax
dec rax
store rax -> [var]
call print function // implicitly uses rax
cmp rax, 0
jg label /// jump-if-greater
Run Code Online (Sandbox Code Playgroud)
(var是一个内存位置,在堆栈上,例如)
并且假设您有2个线程正在运行.一种可能的交错可能是 -
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 |
Run Code Online (Sandbox Code Playgroud)
它有点过于简单,但它显示了如何获得无序打印的值.任何交错也是可能的,只要在相同的线程内保持顺序.
另请注意,您可以拥有类似的东西
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] |
...
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您将获得20次打印两次.