# Java 中的对象级别锁与类级别锁

> 原文： [https://howtodoinjava.com/java/multi-threading/object-vs-class-level-locking/](https://howtodoinjava.com/java/multi-threading/object-vs-class-level-locking/)

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

同步是使所有并发线程在执行中保持同步的过程。 同步避免了由于共享内存视图不一致而导致的内存一致性错误。 当方法声明为**同步**时，该线程持有该方法对象的监视器或[**锁定**](https://howtodoinjava.com/java/multi-threading/how-to-use-locks-in-java-java-util-concurrent-locks-lock-tutorial-and-example/)对象。 如果另一个线程正在执行*同步的*方法，则该线程将被阻塞，直到该线程释放监视器。

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

## 1\. Java 中的对象级别锁定

**对象级别锁定**是一种机制，当我们要同步**非静态方法**或**非静态代码块**时，仅一个线程将能够执行给定类实例上的代码块。 应始终执行它，来使实例级数据线程安全。

对象级别锁定可以通过以下方式完成：

```java
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 中的类级别锁定

**类级别锁**防止在运行时该类的所有可用实例中的多个线程进入`synchronized`块。 这意味着，如果在运行时有`DemoClass`的 100 个实例，则一次只能在一个实例中的任何一个线程上执行`demoMethod()`，而所有其他实例将被其他线程锁定。

应该始终执行类级别锁定**以使静态数据线程安全**。 我们知道 [**静态**](https://howtodoinjava.com/java/basics/java-static-keyword/) 关键字将方法的数据关联到类级别，因此请使用对静态字段或方法的锁定使其在类级别上。

```java
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 `synchronized`方法或块时，它都会获取一个锁，而当线程离开同步方法或块时，它将释放该锁。 即使线程在完成后或由于任何错误或异常而离开同步方法时，也会释放锁定。
4.  Java `synchronized`关键字本质上是**重入者**，这意味着如果同步方法调用了另一个需要相同锁的同步方法，则持有锁的当前线程可以进入该方法而无需获取锁。
5.  如果在同步块中使用的对象为 null，则 Java 同步将抛出[`NullPointerException`](https://howtodoinjava.com/java/exception-handling/how-to-effectively-handle-nullpointerexception-in-java/)。 例如，在以上代码示例中，如果将锁初始化为 null，则“ `synchronized (lock)`”将抛出`NullPointerException`。
6.  Java 中的同步方法使您的应用程序性能降低。 因此，在绝对需要时使用同步。 另外，请考虑使用同步的代码块仅同步代码的关键部分。
7.  静态同步方法和非静态同步方法都可能同时或同时运行，因为它们锁定在不同的对象上。
8.  根据 Java 语言规范，不能将`synchronized`关键字与构造器一起使用。 这是非法的，并导致编译错误。
9.  不要在 Java 中的同步块上的非 final 字段上进行同步。 因为对非 final 字段的引用可能随时更改，然后不同的线程可能会在不同的对象上进行同步，即完全没有同步。
10.  不要使用 String 字面值，因为它们可能在应用程序中的其他地方被引用，并且可能导致死锁。 使用`new`关键字创建的字符串对象可以安全使用。 但是，作为最佳实践，请在我们要保护的共享变量本身上创建一个新的**私有**范围内的`Object`实例 OR 锁。（感谢 Anu 在评论中指出这一点。）

让我知道有关 Java 中对象级别锁与类级别锁的想法和查询。

学习愉快！