Java 当线程尝试调用静态和非静态同步方法时会发生什么?
我有一门课Java 当线程尝试调用静态和非静态同步方法时会发生什么?,java,multithreading,Java,Multithreading,我有一门课 public class ThreadExample extends Thread{ static int count = 0; public static synchronized int increment(){ return count++; } public synchronized int decrement(){ return count--; } } 这里我有一个静态方法和一个非静态方法 第
public class ThreadExample extends Thread{
static int count = 0;
public static synchronized int increment(){
return count++;
}
public synchronized int decrement(){
return count--;
}
}
这里我有一个静态方法和一个非静态方法
第一个线程1调用了同步的方法increment(),它在类级别获得锁。
这里我的问题是,如果另一个thread2正在调用decrement()方法,thread2是否会获取decrement()上的锁以及它是如何工作的?调用同步静态方法会尝试获取类对象的锁。(
ThreadExample
),在调用同步的非静态方法时,尝试获取特定实例对象的锁。因此,本质上您获得了两个不同的锁,因此您的代码不是线程安全的。数据计数
可能由于竞争条件而损坏调用同步静态方法试图获取类对象的锁。(ThreadExample
),在调用同步的非静态方法时,尝试获取特定实例对象的锁。因此,本质上您获得了两个不同的锁,因此您的代码不是线程安全的。数据计数
可能由于竞争条件而损坏关键字synchronized
有两种可能的用途。它可以用作方法的修饰符,也可以用作语句。此外,synchronized
修饰符可以与static
组合,在这种情况下,目标对象将是封闭类而不是封闭实例
如果方法是“静态同步的”,则会在所包含的类的类
对象上获取锁,在ThreadExample.class上就是这样。
虽然它们被编译成不同的字节码,但以下两种方法是等效的:
public class Foo {
// static method with synchronized modifer
public static synchronized void foo1() {
// ...
}
// equivalent synchronized statement
public static void foo2() {
synchronized (Foo.class) {
// ...
}
}
}
public class Foo {
// instance method with synchronized modifier
public synchronized void foo3() {
// ...
}
// equivalent synchronized statement
public void foo4() {
synchronized (this) {
// ...
}
}
}
如果一个方法是同步的
(没有static),则会在实例本身上获取锁。虽然它们被编译成不同的字节码,但以下两种方法是等效的:
public class Foo {
// static method with synchronized modifer
public static synchronized void foo1() {
// ...
}
// equivalent synchronized statement
public static void foo2() {
synchronized (Foo.class) {
// ...
}
}
}
public class Foo {
// instance method with synchronized modifier
public synchronized void foo3() {
// ...
}
// equivalent synchronized statement
public void foo4() {
synchronized (this) {
// ...
}
}
}
因此,increment()
和decreation()
是不同的同步的
,可能存在竞争条件
因此,变量count
没有得到足够的保护,无法防止并发更新
++
和-->
本身不能是原子的,因为递增或递减一个值需要一个读更新写周期。从技术上讲,它可以是原子的,因为一些CPU通过提供相应的指令来提供原子性,这些指令将保留为自己获得的总线/地址,直到执行操作为止。但是JVM并不依赖这些东西
如果需要原子int,您可能需要查看java.util.concurrent.atomic.AtomicInteger
如何在C中进行同步
synchronized
通过虚拟机环境方法MonitorEnter()
和MonitorExit()
实现
陷阱
当您使用synchronized
修改器时,您同步的对象或多或少是公共的
,即其他对象和类也可见。java.lang.Object
的监视功能是public
,它为synchronized
提供了底层功能,以及本机函数MonitorEnter()
/MonitorExit()
和等待池方法wait()
、notify()
和notifyAll()
。如果“其他人”也在使用“您的对象/您的类”进行同步,这可能会导致意外的错误和死锁
因此,实际上不使用synchronized
修饰符,而是在private
锁定对象上使用synchronized
语句已成为一种模式,如下所示:
public class Foo {
private final Object lock = new Object();
public void foo() {
synchronized (lock) {
// ...
}
}
}
现在,Foo
不能再被其他正在同步的人干扰或阻止。您可能会认为这可能有一个合理的用例,但我认为如果您有一个跨对象/类边界锁定的用例,那么设计中可能有一个很大的缺陷——东西不够自包含
如果需要类锁而不是实例锁,只需将变量设为静态
请注意,在执行序列化时,必须注意lock对象。最简单的方法是实际上不使用对象,但是:
public class Lock implements Serializable {}
如果要保存序列化存储,可以声明锁transient
,并在反序列化过程中重新创建锁,但要小心transient final
,它们需要反射或readResolve()
,但情况不同。synchronized
关键字有两种可能的用途。它可以用作方法的修饰符,也可以用作语句。此外,synchronized
修饰符可以与static
组合,在这种情况下,目标对象将是封闭类而不是封闭实例
如果方法是“静态同步的”,则会在所包含的类的类
对象上获取锁,在ThreadExample.class上就是这样。
虽然它们被编译成不同的字节码,但以下两种方法是等效的:
public class Foo {
// static method with synchronized modifer
public static synchronized void foo1() {
// ...
}
// equivalent synchronized statement
public static void foo2() {
synchronized (Foo.class) {
// ...
}
}
}
public class Foo {
// instance method with synchronized modifier
public synchronized void foo3() {
// ...
}
// equivalent synchronized statement
public void foo4() {
synchronized (this) {
// ...
}
}
}
如果一个方法是同步的
(没有static),则会在实例本身上获取锁。虽然它们被编译成不同的字节码,但以下两种方法是等效的:
public class Foo {
// static method with synchronized modifer
public static synchronized void foo1() {
// ...
}
// equivalent synchronized statement
public static void foo2() {
synchronized (Foo.class) {
// ...
}
}
}
public class Foo {
// instance method with synchronized modifier
public synchronized void foo3() {
// ...
}
// equivalent synchronized statement
public void foo4() {
synchronized (this) {
// ...
}
}
}
因此,increment()
和decreation()
是不同的同步的
,可能存在竞争条件
因此,变量count
没有得到足够的保护,无法防止并发更新
++
和-->
本身不能是原子的,因为递增或递减一个值需要一个读更新写周期。从技术上讲,它可以是原子的,因为一些CPU通过prov为它提供原子性