线程和同步问题

5
在某些情况下,以下程序实际上会停止(因为线程2),但它不应该。为什么会发生这种情况?
线程1:基本上锁定全局变量并执行while循环。 线程2:尝试获取全局变量的锁,如果成功,则继续停止程序。
但是,线程1首先启动,所以从技术上讲,线程2永远不应该被调用,因此程序永远不应该退出。
static Integer global = 30;

public static synchronized void setVar(int x, String from)
{
    System.out.println(global + " " + x + " - " + from);
    global = x;
}
public static void main(String [] args)
{
    Thread thr1 = new Thread(new Runnable()
    {
        @Override
        public void run() 
        {
            synchronized(global)
            {
                while(true)
                {
                    setVar((int) (Math.random() * 30), "Thread 1");
                }
            }
        }

    });

    Thread thr2 = new Thread(new Runnable()
    {
        @Override
        public void run() 
        {   
            synchronized(global)
            {
                setVar((int) (Math.random() * 30), "Thread 2");
                System.exit(0);
            }
        }

    });

    thr1.start();
    thr2.start();
}

输出(我偶尔会得到的)

30 19 - 线程 2

2个回答

4

thr1启动并在遇到synchronized之前被停止,此时thr2获取锁并退出是完全可能的。

我唯一担心的是(int)(Math.random()* 30)如何评估为19。现在这真的很奇怪。


2
它被转换为整数 0 < x < 29 - Mathew Kurian
@mk1 - 你是美国人,对吧...你总能认出一个美国人...没有讽刺的感觉。 :) - OldCurmudgeon
你能详细解释一下“parked”的概念吗?在这个上下文中,我觉得有些困惑。 - Mathew Kurian
1
JVM 可以随时决定停止任何线程,以便让另一个线程获得一些处理器时间。当在单核 CPU 上运行多线程算法时,这种情况最为常见 - JVM 会为每个线程安排一些活动时间,然后将其挂起并允许其他线程获得一些时间。 - OldCurmudgeon

1
在所有线程相关问题中,有90%的问题都与线程执行顺序无法确定有关,这是第一要点。
在您的例子中:
Thread 1: created, put on hold for whatever reason
Thread 2: created, runs to synchronized and gets lock.
Thread 1: resumed, runs to synchronized, has to wait.

如果您编写使用这种同步模型的线程化代码,您需要为所有情况做好准备,因为谁能说出实际发生的情况。
此外,关于“永远不应该被调用”的问题。是的,这很不可能,但即使机会只有1%,这仍意味着在100次运行中,它在统计上至少会发生一次。

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