java中的对象级别锁定 VS 类级别锁定

时间:2020-02-23 14:35:28  来源:igfitidea点击:

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

为什么你需要同步?

让我们在举例的帮助下了解这一点。
假设我们想要计算我们为特定URL获得的请求数。
如果我们同时获得两个请求,则计数可能不一致。

没有同步:

package org.igi.theitroad;
 
public class RequestCounter {
 
 private int count;
 
 public int incrementCount()
 {
  count++;
  return count;
 }
}

例如:线程T1看到数量为20并将其递增到21.同时,线程T2也看到算作20并将其递增到21.这表明计数变得不一致。

具有同步:

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

  • 同步方法
  • 同步块
You can not use synchronized with  instance or class variables.

同步方法

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

package org.igi.theitroad;
 
public class RequestCounter {
 
 private int count;
 
 public synchronized int incrementCount()
 {
  count++;
  return count;
 }
}

例如:线程T1看到计数为20并将其递增到21.同时,线程T2现在将看到计数为21并将其递增至22.

同步块

我们可以使用块以IncrementCount()方法中的关键部分同步关键部分,因此没有两个线程可以同时访问块。

package org.igi.theitroad;
 
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;
  }

使用Synchronized块并锁定其他对象:

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

Class Level Locking:

类级别锁定意味着要同步静态方法或者块,以便仅为全类类的一个线程访问它。
如果我们有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
  }
 }

这里如果来自方法1的任何线程调用方法2,它已经在此对象上锁定,因此执行安全。