为何下面这段程序不能结束?
class T implements Runnable {
boolean f = true; public void run() {
while (f) {
}
}
public void stopRunning() {
f = false;
}
}public class TestThread {
public static void main(String[] args) throws Exception {
T t = new T();
Thread th = new Thread(t);
th.start();
for (int i = 0; i < 5; i++) {
System.out.println("Alive:" + th.isAlive());
Thread.sleep(10); //这行注释掉程序可以结束
}
t.stopRunning();
}
}
class T implements Runnable {
boolean f = true; public void run() {
while (f) {
}
}
public void stopRunning() {
f = false;
}
}public class TestThread {
public static void main(String[] args) throws Exception {
T t = new T();
Thread th = new Thread(t);
th.start();
for (int i = 0; i < 5; i++) {
System.out.println("Alive:" + th.isAlive());
Thread.sleep(10); //这行注释掉程序可以结束
}
t.stopRunning();
}
}
解决方案 »
- 关于Object中的hashCode()方法。
- 用JAI处理相机里拷出的图片,另存后颜色等不对
- swing中如何进行窗体传值
- 关于java调用python程序的问题
- java和Oracle中文字符比较问题?
- 装了jbuildx出了个怪事情啊,怎样解决啊?
- 请教一个有问题的小程序!
- 请问如何在java中设定空间大小
- 分享:写了一个 java 调用 C语言 开发的 windows 动态库的范例
- 我想在JInternalFrame中放入JDialog,可是每次最小化后,再最大化JDialog就跑到底面处了,出不来,不知各位有没有好的解决方按?
- 解释一下 怎么两个线程会抢起来?
- java如何打开一个本地的网页
试试
这个问题好像是跟内存模型有关,
我是看到书上说会有这种问题,
不过我自己没实验出来
public void run() {
while (f) {
}
}
这段代码在某些jvm上可以被合法优化为:
public void run() {
if (f) {
while(true) {
}
}
}
Effective Java 讲到了源生类型(primitive type)的同步问题
即 int, char, boolean ... 等的同步问题有时人们说,源生类型除了 long 和 double 以外,其他都是“天生线程安全”的,不需要做特别的同步,Effective Java里指出了这种说法的不实之处。根据Java的规范,除了 long 和 double 之外,其他所有的源生类型的读操作和写操作都有原子性保护,
就是说,在一个多线程的环境下,一个 int 变量即使被不同的线程读/写,
也保证不会出现某个线程读到一个“刚被写了一个字节,其他三个字节还是原来旧的二进制值”的混乱值(arbitrary value)但是“线程安全”包含两个方面:1 - 对所有的线程,都以“稳定的状态”呈现
2 - 所有的线程都能及时看到最新的更改上面说的源生类型的 读 或 写 的天生原子性,保证了第一点,没有保证第二点,及一个源生类型变量的值在一个线程中被改变,这个改变不能保证被另一个线程及时看到,甚至不能保证另一个线程最终能不能看到。因为有这样的特性,所以4楼提到的那种运行时优化是合法的,在某些较早的jvm上也是确实存在的。源生类型已经满足了第一点,要再满足第二点,加 volatile 关键字即可。另外,引用(reference)在这个问题上,与源生类型非常相似,Java 1.5以后,reference的同步可以用 volatile 来支持。要注意的是 volatile 后的源生类型变量只是满足了 单个操作 的线程安全,向下面这样的:volatile int a = 1;void increase() {
a++;
}
实际包含了读和写两个操作,volatile 不能为其提供原子性保护,这就是为什么会有 AtomicInteger 等类,这些类为源生类型提供一些原子性的读写方法。
前面几位说的都挺好,尤其是推荐你去看看ticmy的Blog关于:“Thread.sleep(10); //这行注释掉程序可以结束”
这其实是你误会了线程启动执行的真实时机问题,并不是你调用了start(),线程就立即开始run()了。
也就说:可能在你子线程还没启动完毕,你的for循环就已经结束,那么就会触发将stopRunning(),之后子线程才正式开始执行,而此时f已经是false。所以你误以为是程序可以正常结束,但其实是因为 while(f) 刚想开始第一次循环,f 就已经是false 了,所以根本没有循环成。所以关键问题是确保子线程已经开始执行再调用stopRunning(),而非sleep()自身的原因。
start(),run()的关系我是了解的。这个程序的问题是在一台机器上运行不能结束,明显是因为子线程不能结束而导致main线程不能结束。
Thread.sleep(10); 的目的是保证大部分执行情况下子线程能在main线程执行for循环时能执行。
再次感谢各位!
说法不准确。main()函数结束后,main线程即结束,并启动Destory线程。但子线程不结束,只是会阻止整个程序结束,并不会阻止main线程结束。另外,如果子线程是守护线程,则不能阻止程序结束。