Maxgmer Asked:2020-02-08 23:33:57 +0800 CST2020-02-08 23:33:57 +0800 CST 2020-02-08 23:33:57 +0800 CST 关于同步的问题 772 我是否理解正确,如果一段synchronized代码开始执行,直到执行完毕,java不会跳转到另一个线程? 如果是这样,那么为什么synchronized一个表达式,例如变量的初始化,放在一个块中,如果 java 不能在不执行至少一个操作的情况下跳转到另一个线程,因为 操作到一半无法执行? java 2 个回答 Voted Best Answer user194374 2020-02-09T02:20:10+08:002020-02-09T02:20:10+08:00 Javasynchronized中的块具有这样的属性,即如果一个线程已进入该块,那么另一个线程将能够在第一个线程离开之前进入该块。简单地说,如果一个线程正在执行一个块,其他希望执行该块的线程将等待。synchronized 有时人们认为,如果一个线程进入synchronized-block,那么所有其他线程都会被挂起。这不是真的。其他线程继续执行,直到它们遇到同一个块。 但事实上,一切都有点复杂。该块synchronized使用某个对象作为“屏障”(某个对象是 的后代java.lang.Object,因此int它无法同步)。如果你在同一个对象上声明了两个同步块,那么如果执行了一个块,其他线程将无法进入这两个块中的任何一个。例子: Object o; synchronized(o) { // Блок 1 } synchronized(o) { // Блок 2 } 如果有任何线程正在执行块 1,则没有线程可以同时执行块 2。相反,如果有任何线程正在执行块 2,则没有线程可以同时执行块 1。 还应该注意的是,一个类可以有synchronized-methods: class Test { public synchronized void f() { /* ... */ } public synchronized void g() { /* ... */ } } 这隐含地假定同步对象是该类的一个实例。换句话说,如果任何线程进入synchronized了类实例的方法之一,则其他线程将无法进入该实例的任何其他synchronized方法。但是你需要记住,另一个线程将能够进入同一个类synchronized的另一个实例的方法。(如果我说在这种情况下同步发生在 上,也许会更清楚this。) 让我们继续讨论问题的第二部分。为什么一个变量的初始化是在一个synchronized-block中取出来的?因为关于单个Java操作的原子性的说法是不正确的。甚至下一个语句 int i = 0; 在一般情况下可能不是原子的。事实上, 原子性意味着无法“看到”操作的中间状态。例如,上面的代码可以编译成两条处理器指令: xor eax,eax mov [i], eax 如果另一个线程“楔入” 和 之间xor,mov那么它将“看到”中间状态。关于更复杂的类型初始化,我们能说些什么 String s = "строка"; 更何况 Object o = big_ang_long_running_function(); Anton Shchyrov 2020-02-09T00:00:31+08:002020-02-09T00:00:31+08:00 不。synchronized在构造中传递指向对象的指针。所以 Java 保证当这样一个块被调用时,调用synchronized 同一个对象的第二个线程将进入休眠状态,直到第一个块被执行。
Java
synchronized
中的块具有这样的属性,即如果一个线程已进入该块,那么另一个线程将能够在第一个线程离开之前进入该块。简单地说,如果一个线程正在执行一个块,其他希望执行该块的线程将等待。synchronized
有时人们认为,如果一个线程进入
synchronized
-block,那么所有其他线程都会被挂起。这不是真的。其他线程继续执行,直到它们遇到同一个块。但事实上,一切都有点复杂。该块
synchronized
使用某个对象作为“屏障”(某个对象是 的后代java.lang.Object
,因此int
它无法同步)。如果你在同一个对象上声明了两个同步块,那么如果执行了一个块,其他线程将无法进入这两个块中的任何一个。例子:如果有任何线程正在执行块 1,则没有线程可以同时执行块 2。相反,如果有任何线程正在执行块 2,则没有线程可以同时执行块 1。
还应该注意的是,一个类可以有
synchronized
-methods:这隐含地假定同步对象是该类的一个实例。换句话说,如果任何线程进入
synchronized
了类实例的方法之一,则其他线程将无法进入该实例的任何其他synchronized
方法。但是你需要记住,另一个线程将能够进入同一个类synchronized
的另一个实例的方法。(如果我说在这种情况下同步发生在 上,也许会更清楚this
。)让我们继续讨论问题的第二部分。为什么一个变量的初始化是在一个
synchronized
-block中取出来的?因为关于单个Java操作的原子性的说法是不正确的。甚至下一个语句在一般情况下可能不是原子的。事实上, 原子性意味着无法“看到”操作的中间状态。例如,上面的代码可以编译成两条处理器指令:
如果另一个线程“楔入” 和 之间
xor
,mov
那么它将“看到”中间状态。关于更复杂的类型初始化,我们能说些什么更何况
不。
synchronized
在构造中传递指向对象的指针。所以 Java 保证当这样一个块被调用时,调用synchronized
同一个对象的第二个线程将进入休眠状态,直到第一个块被执行。