第五章 java中的对象级锁定与类级锁定


同步是将对共享资源的访问限制为仅一个线程的能力。当两个或多个线程需要访问共享资源时,必须有某种机制使得共享资源只能由一个线程使用。我们可以实现它的过程称为同步。

为什么需要同步?

让我们借助示例来理解这一点。 假设您想计算针对特定 URL 获得的请求数。如果同时收到两个请求,那么 count 可能会不一致。

不同步:

package org.arpit.java2blog;

public class RequestCounter {

private int count;

public int incrementCount()
{
  count++;
  return count;
}
}

例如: 线程 T1 看到 count 为 20 并递增到 21。同时线程 t2 也看到 count 为 20 并将其递增到 21。这表明 count 变得不一致。

同步:

您可以使用两种方式实现同步。

  • 同步方法
  • 同步块

同步方法

您可以使整个 incrementCount() 方法同步,因此没有两个线程可以并行访问它。

package org.arpit.java2blog;

public class RequestCounter {

private int count;

public synchronized int incrementCount()
{
  count++;
  return count;
}
}

例如: 线程 T1 看到计数为 20 并将其增加到 21。同时,线程 t2 现在将看到计数为 21 并将其增加到 22。

同步块

您可以在 incrementCount() 方法中使用 block 来同步临界区,这样就没有两个线程可以同时访问 block。

package org.arpit.java2blog;

public class RequestCounter {

private int count;

public int incrementCount() {
  synchronized (this) {
   count++;
   return count;
  }
}
}

例如: 线程 T1 看到计数为 20 并将其增加到 21。同时,线程 t2 现在将看到计数为 21 并将其增加到 22。

java中有两种类型的锁定。

  • 对象级锁定

  • 类级别锁定

对象级锁定:

对象级锁定意味着您希望同步非静态方法或块,以便该实例一次只能由一个线程访问。如果要保护非静态数据,则使用它。

您可以通过以下方式实现对象级锁定。

使方法同步:

public synchronized int incrementCount()
{
}

使用同步块并锁定:

public int incrementCount() {
  synchronized (this) {
   count++;
   return count;
  }

使用同步块并锁定其他对象:

private final Object lock=new Object();
public int incrementCount() {
  synchronized (lock) {
   count++;
   return count;
  }

类级别锁定:

类级锁定意味着您要同步静态方法或块,以便整个类只能由一个线程访问。如果您有 10 个类实例,则只有一个线程一次只能访问任何一个实例的一种方法或块。如果要保护静态数据,则使用它。

这可以通过以下方式实现:

使静态方法同步:

public static synchronized int incrementCount()
{
}

在 .class 上使用同步块和锁定:

public int incrementCount() {
  synchronized (RequestCounter.class) {
   count++;
   return count;
  }

使用同步块并锁定其他一些静态对象:

private final static Object lock=new Object();
public int incrementCount() {
  synchronized (lock) {
   count++;
   return count;
  }

两个线程可以同时执行静态和非静态方法吗?

是的,由于两个线程将获取不同对象的锁,因此它们可以同时执行而不会出现任何问题。

如果一个类的方法是同步的,而同一个类的另一个方法是不同步的?它们可以由两个线程同时执行吗?

是的,因为一个线程需要锁才能进入同步块,而第二个线程将执行不需要任何锁的非同步方法,所以它可以并发执行。

从另一个同步方法调用同步方法是否安全?

是的,从另一个同步方法调用同步方法是安全的,因为当您调用同步方法时,您将获得对该对象的锁定,而当您调用同一类的另一个同步方法时,执行是安全的,因为它已经锁定这个对象。 例如:

public synchronized void method1() {
  method2();
  // some code
}

public synchronized void method2() {
  // some code
}

你实际上正在这样做。

public void method1() {
  synchronized (this) {
   method2();
   // some code
  }

}

public void method2() {
  synchronized (this) {
  // some code
  }
}

这里如果任何线程从method1调用method2,它已经锁定了这个对象,因此执行是安全的。


原文链接:https://codingdict.com/