控制台上的其他信息与堆栈跟踪未按正确顺序打印。

5

为什么以下Java程序打印的堆栈跟踪在控制台屏幕上显示时没有按正确顺序显示? 它会与屏幕上的其他消息混合在一起。

是否涉及任何并行性导致此问题出现?

Java程序:

package evm;

public class Client {

    public static void main(String[] args) {
        EVM evm = new EVM();
        
        try {
            evm.setCandidates(90);   /**An Exception thrown here**/
        } catch (CandidatesOutOfLimitsException e) {
            e.printStackTrace();
            //System.out.print(e.getMessage());
        }
        
        try {
            evm.voteForCandidate(43);    /**An Exception thrown here**/
        } catch (BallotUnitOffException e1) {
            e1.printStackTrace();
            //System.out.print(e1.getMessage());
        }

        evm.pressBallotButton();
        
        System.out.println(evm);  //other messages
        evm.switchOn();
        System.out.println(evm);  //other messages
        
        try {
            evm.voteForCandidate(43);    /**An Exception thrown here**/
        } catch (BallotUnitOffException e) {
            e.printStackTrace();
            //System.out.print(e.getMessage());
        }
    }

}

我已经对抛出异常的代码行进行了注释。

运行1:

evm.CandidatesOutOfLimitsException: Number of Candidates cannot exceed 64
    at evm.EVM.setCandidates(EVM.java:41)
    at evm.Client.main(Client.java:9)
evm.BallotUnitOffException: Ballot Unit is not On
    at evm.BallotUnit.pressCandidateButton(BallotUnit.java:38)
    at evm.EVM.voteForCandidate(EVM.java:59)
    at evm.Client.main(Client.java:16)
evm.BallotUnitOffException: Ballot Unit is not On
    at evm.BallotUnit.pressCandidateButton(BallotUnit.java:38)
    at evm.EVM.voteForCandidate(EVM.java:59)
    at evm.Client.main(Client.java:28)

Control Unit State: evm.Off@42a57993
On Lamp: evm.Off@15db9742Ballot Unit: Ready Lamp: evm.Off@6d06d69c
Slide Switch:evm.SlideSwitchOne@7852e922
Ballot Unit: Ready Lamp: evm.Off@4e25154f
Slide Switch:evm.SlideSwitchTwo@70dea4e
Ballot Unit: Ready Lamp: evm.Off@5c647e05
Slide Switch:evm.SlideSwitchThree@33909752
Ballot Unit: Ready Lamp: evm.Off@55f96302
Slide Switch:evm.SlideSwitchFour@3d4eac69


Control Unit State: evm.On@28d93b30
On Lamp: evm.On@75b84c92Ballot Unit: Ready Lamp: evm.On@6bc7c054
Slide Switch:evm.SlideSwitchOne@7852e922
Ballot Unit: Ready Lamp: evm.On@232204a1
Slide Switch:evm.SlideSwitchTwo@70dea4e
Ballot Unit: Ready Lamp: evm.On@4aa298b7
Slide Switch:evm.SlideSwitchThree@33909752
Ballot Unit: Ready Lamp: evm.On@7d4991ad
Slide Switch:evm.SlideSwitchFour@3d4eac69

运行第二步:

evm.CandidatesOutOfLimitsException: Number of Candidates cannot exceed 64
    at evm.EVM.setCandidates(EVM.java:41)
    at evm.Client.main(Client.java:9)
evm.BallotUnitOffException: Ballot Unit is not On
    at evm.BallotUnit.pressCandidateButton(BallotUnit.java:38)
    at evm.EVM.voteForCandidate(EVM.java:59)
    at evm.Client.main(Client.java:16)

Control Unit State: evm.Off@42a57993
On Lamp: evm.Off@15db9742Ballot Unit: Ready Lamp: evm.Off@6d06d69c
Slide Switch:evm.SlideSwitchOne@7852e922
Ballot Unit: Ready Lamp: evm.Off@4e25154f
Slide Switch:evm.SlideSwitchTwo@70dea4e
Ballot Unit: Ready Lamp: evm.Off@5c647e05
Slide Switch:evm.SlideSwitchThree@33909752
Ballot Unit: Ready Lamp: evm.Off@55f96302
Slide Switch:evm.SlideSwitchFour@3d4eac69


Control Unit State: evm.On@28d93b30
On Lamp: evm.On@75b84c92Ballot Unit: Ready Lamp: evm.On@6bc7c054
Slide Switch:evm.SlideSwitchOne@7852e922
Ballot Unit: Ready Lamp: evm.On@232204a1
Slide Switch:evm.SlideSwitchTwo@70dea4e
Ballot Unit: Ready Lamp: evm.On@4aa298b7
Slide Switch:evm.SlideSwitchThree@33909752
Ballot Unit: Ready Lamp: evm.On@7d4991ad
Slide Switch:evm.SlideSwitchFour@3d4eac69

evm.BallotUnitOffException: Ballot Unit is not On
    at evm.BallotUnit.pressCandidateButton(BallotUnit.java:38)
    at evm.EVM.voteForCandidate(EVM.java:59)
    at evm.Client.main(Client.java:28)

每次运行时,我都会得到其他一些模式。有人能解释这种行为吗?
我正在使用:
Eclipse Java EE IDE for Web Developers.
版本:Luna Release(4.4.0)
构建ID:20140612-0600
抱歉问题很长。

4
println() 是线程安全的,但是 printStackTrace()println() 的组合可能会导致像这样的结果,因为其中一个方法写入标准错误流,而另一个方法则写入标准输出流。尽管输出被分别记录,但仍可能交错显示在您的控制台上。 - TheLostMind
2
@TheLostMind 那应该是一个答案。 - fge
1
@TheLostMind 我怎样才能只写入一个流? - Shri
2
e.printStackTrace(System.out) - schtever
1
没错。默认情况下,e.printStacktrace 打印到 System.err。 - schtever
显示剩余5条评论
1个回答

5
这与标准输出和错误流的实现有关,而不是Eclipse本身。 System.outSystem.err都是PrintStream对象,可以传递缓冲流并不会自动刷新数据到目标位置。由于这两个不同的流内部都使用缓冲,所以你写入它们的数据可能会交错,因为这些流可能在不同时间决定何时刷新(缓冲区可能在不同时间填充)。
在打印前两个堆栈跟踪后调用System.err.flush(),然后在向标准输出流打印后调用System.out.flush()应该获得一致的结果。

Schtever在问题的评论中提出了另一种方法,您对此有何看法?哪个更好? - Shri
@Shri 这样做是可行的,但将错误堆栈跟踪打印到标准输出并不常规,似乎更像是一种变通方法。 - M A
我知道这很烦人,但你能告诉我为什么吗? - Shri
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - M A
不,我只尝试过使用printStackTrace()。嗯,我得到了答案,但是我想要一个好的解释,这样能够让任何遇到这个问题的人受益。你做得很好。 - Shri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接