🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Java `synchronized`关键字 > 原文: [https://howtodoinjava.com/java/multi-threading/java-synchronized/](https://howtodoinjava.com/java/multi-threading/java-synchronized/) **Java `synchronized`关键字**将块或方法标记为临界区。 临界区是一次仅执行一个线程的线程,该线程持有同步部分的锁。 `synchronized`关键字有助于编写应用程序的[并发](https://howtodoinjava.com/java-concurrency-tutorial/)部分,以保护此块中的共享资源。 `synchronized`关键字可以用于: * 一个代码块 * 一个方法 ## 1\. Java 同步块 #### 1.1 语法 编写同步块的一般语法如下。 此处 `lockObject`是对对象的引用,该对象的锁与同步语句表示的监视器关联。 ```java synchronized( lockObject ) { // synchronized statements } ``` #### 1.2 内部工作 当线程要在同步块内执行同步语句时,必须获得`lockObject`监视器的锁定。 一次,只有一个线程可以获取锁对象的监视器。 因此,所有其他线程必须等到当前已获得锁的该线程完成执行。 通过这种方式,`synchronized`关键字可确保一次仅一个线程将执行同步的块语句,从而防止多个线程破坏该块内部的共享数据。 请记住,如果一个线程进入睡眠状态(使用`sleep()`方法),则它不会释放锁。 在此休眠时间,没有线程将执行同步的块语句。 如果`'synchronized (lock)'`中使用的锁定对象为`null`,则 Java 同步将抛出`NullPointerException`。 #### 1.3 Java 同步块示例 Java 程序演示同步块的用法。 在给定的示例中,我们具有使用方法`printNumbers()`的`MathClass`。 此方法将打印从 1 到参数 N 的数字。 请注意,`printNumbers()`方法中的代码在同步块内部。 ```java public class MathClass { void printNumbers(int n) throws InterruptedException { synchronized (this) { for (int i = 1; i <= n; i++) { System.out.println(Thread.currentThread().getName() + " :: "+ i); Thread.sleep(500); } } } } ``` 我创建了两个线程,它们开始完全同时执行`printNumbers()`方法。 由于块被同步,因此仅允许一个线程访问,而另一个线程必须等待直到第一个线程完成。 ```java public class Main { public static void main(String args[]) { final MathClass mathClass = new MathClass(); //first thread Runnable r = new Runnable() { public void run() { try { mathClass.printNumbers(3); } catch (InterruptedException e) { e.printStackTrace(); } } }; new Thread(r, "ONE").start(); new Thread(r, "TWO").start(); } } ``` 程序输出。 ```java ONE :: 1 ONE :: 2 ONE :: 3 TWO :: 1 TWO :: 2 TWO :: 3 ``` ## 2\. Java 同步方法 #### 2.1 语法 编写同步方法的一般语法如下。 此处`lockObject`是对对象的引用,该对象的锁与同步语句表示的监视器关联。 ```java <access modifier> synchronized method( parameters ) { // synchronized code } ``` #### 2.2 内部工作 与同步块类似,线程必须使用同步方法来获取关联的监视对象上的锁。 如果采用同步方法,则锁定对象为: * `.class`对象 - 如果该方法是静态的。 * `this`对象 - 如果方法不是静态的。 `this`是指在其中调用同步方法的当前对象的引用。 > 阅读更多: [Java 中的对象级别锁与类级别锁](https://howtodoinjava.com/java/multi-threading/object-vs-class-level-locking/) Java `synchronized`关键字本质上是**重入符**,这意味着如果同步方法调用了另一个需要相同锁定的同步方法,则持有锁定的当前线程可以进入该方法而无需获取锁定。 #### 2.3 Java 同步方法示例 与同步块示例类似,我们可以在`printNumber()`方法上应用`synchronized`关键字,这将使该方法成为同步方法。 现在,如果再次运行示例,我们将获得类似的输出。 ```java public class MathClass { synchronized void printNumbers(int n) throws InterruptedException { for (int i = 1; i <= n; i++) { System.out.println(Thread.currentThread().getName() + " :: "+ i); Thread.sleep(500); } } } ``` 程序输出: ```java ONE :: 1 ONE :: 2 ONE :: 3 TWO :: 1 TWO :: 2 TWO :: 3 ``` 在评论中把您的问题交给我。 学习愉快!