我正在尝试线程优先级的影响,当runln在run方法中保留在注释中时,两个线程同时结束并且我不理解这种行为,你能解释一下吗?谢谢。
public class Main {
public static void main(String[] args) {
Test t1 = new Test("Thread #1");
Test t2 = new Test("Thread #2");
t1.thread.setPriority(10);
t2.thread.setPriority(1);
t1.thread.start();
t2.thread.start();
try {
t1.thread.join();
t2.thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t1.thread.getName() + ": " + t1.count);
System.out.println(t2.thread.getName() + ": " + t2.count);
System.out.println("End of main thread.");
}
}
public class Test implements Runnable{
public Thread thread;
static boolean stop = false;
int count = 0;
public Test(String name){
thread = new Thread(this, name);
}
@Override
public void run(){
for(int i = 0; i < 10000000 && stop == false; i++){
count = i;
//System.out.println(count + " " + thread.getName());
}
stop = true;
System.out.println("End of " + thread.getName());
}
}
without println with println End of Thread #1 End of Thread #1 End of Thread #2 End of Thread #2 Thread #1: 9999999 Thread #1: 9999999 Thread #2: 9999999 Thread #2: 3265646 End of main thread. End of main thread.
答案 0 :(得分:4)
您的两个线程在没有正确同步的情况下访问共享的可变变量。在这种情况下,没有关于线程何时(或者是否)将了解另一个线程所做更改的保证。在您的情况下,一个线程所做的更改根本不会被另一个线程注意到。请注意,对于像boolean
这样的原始数据类型,不读取最新值是最糟糕的事情,对于非原始数据类型,甚至更糟的问题,即可能发生不一致的结果。
插入print语句具有同步线程的副作用,因为PrintStream
执行内部同步。由于没有保证System.out
将包含这样的同步打印流实现,这是一个特定于实现的副作用。
如果您将stop
的声明更改为
static volatile boolean stop = false;
线程将在每次迭代中重新读取共享堆中的值,并立即对更改做出反应,但代价是降低整体性能。
请注意,仍然无法保证此代码按预期工作,因为没有任何保证,线程优先级没有任何影响,也没有线程并行运行。线程调度是实现和环境相关的行为。例如。你可能会发现优先级最高的线程不会先完成它的循环,而只是首先启动的线程。
答案 1 :(得分:3)
澄清:线程/进程&#34;优先级的唯一目的,&#34;在任何操作系统的任何语言环境中,建议到操作系统&#34;这两个中的哪一个应该是,我认为,先运行& #39;&#34;如果他们两个碰巧是偶然的&#34;可跑的&#34;并且必须选择只运行其中一个。
(根据我的经验,这个实践中最好的例子是Unix / Linux nice
命令,它自动以显着的数量减少命令的执行优先级。执行少量I / O的CPU密集型工作负载实际上可以从中获得优先级降低。
正如其他回答者已经强调的那样,不可能预测&#34;实际会发生什么,&#34;永远不能用来改变这个前提。您必须显式使用适当的同步原语,以确保您的代码在所有情况下都能正常执行。