Java中对象锁与类锁的比较(synchronized)

在Java中,synchronized代码块一次只能由一个线程执行。 另外,java支持多线程并发执行。 这可能会导致两个或多个线程同时访问相同的字段或对象。

同步是使所有正在执行的并发线程保持同步的过程。 同步避免了由于共享内存视图不一致而导致的内存一致性错误。 当一个方法被声明为synchronzied时; 线程持有该方法对象的monitor或lock对象。 如果另一个线程正在执行同步方法,则您的线程将被阻塞,直到该线程释放监视器。

请注意,我们可以在类中定义的方法或块上使用synchronized关键字。 在类定义中,synchronized 关键字不能与变量或属性一起使用。

1.Java中的对象级锁(Object level lock)


当我们想要同步非静态方法或非静态代码块时,对象级锁是一种机制,以便只有一个线程能够在给定的类实例上执行代码块。 应该始终这样做以确保实例级数据线程安全。

对象级锁定可以按如下方式完成:

public class DemoClass
{
  public synchronized void demoMethod(){}
}
 
or
 
public class DemoClass
{
  public void demoMethod(){
    synchronized (this)
    {
      //other thread safe code
    }
  }
}
 
or
 
public class DemoClass
{
  private final Object lock = new Object();
  public void demoMethod(){
    synchronized (lock)
    {
      //other thread safe code
    }
  }
}

2.Java中的类级锁(Class level lock)


类级锁可防止多个线程在运行时进入该类的任何可用实例中的同步块。 这意味着如果在运行时有 100 个 DemoClass 实例,那么一次只有一个线程能够在任一实例中执行 demoMethod(),而所有其他实例将被其他线程锁定。

应始终执行类级锁定以确保静态数据线程安全。 我们知道 static 关键字将方法的数据与类级别关联,因此在静态字段或方法上使用锁定以使其在类级别上。

public class DemoClass
{
  //Method is static
  public synchronized static void demoMethod(){
 
  }
}
 
or
 
public class DemoClass
{
  public void demoMethod()
  {
    //Acquire lock on .class reference
    synchronized (DemoClass.class)
    {
      //other thread safe code
    }
  }
}
 
or
 
public class DemoClass
{
  private final static Object lock = new Object();
 
  public void demoMethod()
  {
    //Lock object is static
    synchronized (lock)
    {
      //other thread safe code
    }
  }
}

3. 对象级锁与类级锁 – 重要说明

  1. Java 中的同步保证没有两个线程可以同时或同时执行同步方法,该方法需要相同的锁。
  2. Synchronized 关键字只能与方法和代码块一起使用。 这些方法或块可以是静态的或非静态的。
  3. 当线程进入 Java 同步方法或块时,它会获取锁;每当线程离开同步方法或块时,它都会释放锁。 即使线程在完成后或由于任何错误或异常而离开同步方法,锁也会被释放。
  4. Java的synchronized关键字本质上是re-entrant,这意味着如果一个同步方法调用另一个需要相同锁的同步方法,那么当前持有锁的线程可以进入该方法而无需获取锁。
  5. 如果synchronized块中使用的对象为null,Java同步将抛出NullPointerException。 例如,在上面的代码示例中,如果lock初始化为null,“synchronized(lock)”将抛出NullPointerException。
  6. Java 中的同步方法会增加应用程序的性能成本。 因此,在绝对需要时使用同步。 另外,请考虑使用同步代码块仅同步代码的关键部分。
  7. 静态同步和非静态同步方法可能同时或同时运行,因为它们锁定不同的对象。
  8. 根据Java语言规范,不能在构造函数中使用synchronized关键字。 这是非法的,会导致编译错误。
  9. 不要在 Java 中同步块的非最终字段上进行同步。 因为非最终字段的引用可能随时更改,然后不同的线程可能在不同的对象上同步,即根本不同步。
  10. 不要使用字符串文字,因为它们可能会在应用程序中的其他位置被引用,并可能导致死锁。 使用new关键字创建的字符串对象可以安全地使用。 但作为最佳实践,创建一个新的私有范围对象实例或锁定我们想要保护的共享变量本身。 [感谢 Anu 在评论中指出这一点。

参考资料

Class Level Lock in Java - GeeksforGeeks

猜你喜欢

转载自blog.csdn.net/keeppractice/article/details/131828437
今日推荐