Java synchronized关键字

Java synchronized关键字

原文: https://howtodoinjava.com/java/multi-threading/java-synchronized/

Java synchronized关键字将块或方法标记为临界区。 临界区是一次仅执行一个线程的线程,该线程持有同步部分的锁。

synchronized关键字有助于编写应用程序的并发部分,以保护此块中的共享资源。

synchronized关键字可以用于:

  • 一个代码块
  • 一个方法

1. Java 同步块

1.1 语法

编写同步块的一般语法如下。 此处 lockObject是对对象的引用,该对象的锁与同步语句表示的监视器关联。

synchronized( lockObject ) 
{
   // synchronized statements
}

1.2 内部工作

当线程要在同步块内执行同步语句时,必须获得lockObject监视器的锁定。 一次,只有一个线程可以获取锁对象的监视器。 因此,所有其他线程必须等到当前已获得锁的该线程完成执行。

通过这种方式,synchronized关键字可确保一次仅一个线程将执行同步的块语句,从而防止多个线程破坏该块内部的共享数据。

请记住,如果一个线程进入睡眠状态(使用sleep()方法),则它不会释放锁。 在此休眠时间,没有线程将执行同步的块语句。

如果'synchronized (lock)'中使用的锁定对象为null,则 Java 同步将抛出NullPointerException

1.3 Java 同步块示例

Java 程序演示同步块的用法。 在给定的示例中,我们具有使用方法printNumbers()MathClass。 此方法将打印从 1 到参数 N 的数字。

请注意,printNumbers()方法中的代码在同步块内部。

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()方法。 由于块被同步,因此仅允许一个线程访问,而另一个线程必须等待直到第一个线程完成。

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();
    }
}

程序输出。

ONE :: 1
ONE :: 2
ONE :: 3

TWO :: 1
TWO :: 2
TWO :: 3

2. Java 同步方法

2.1 语法

编写同步方法的一般语法如下。 此处lockObject是对对象的引用,该对象的锁与同步语句表示的监视器关联。

<access modifier> synchronized method( parameters ) 
{
    // synchronized code
}

2.2 内部工作

与同步块类似,线程必须使用同步方法来获取关联的监视对象上的锁。 如果采用同步方法,则锁定对象为:

  • .class对象 - 如果该方法是静态的。
  • this对象 - 如果方法不是静态的。 this是指在其中调用同步方法的当前对象的引用。

阅读更多: Java 中的对象级别锁与类级别锁

Java synchronized关键字本质上是重入符,这意味着如果同步方法调用了另一个需要相同锁定的同步方法,则持有锁定的当前线程可以进入该方法而无需获取锁定。

2.3 Java 同步方法示例

与同步块示例类似,我们可以在printNumber()方法上应用synchronized关键字,这将使该方法成为同步方法。 现在,如果再次运行示例,我们将获得类似的输出。

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);
        }
    }
}

程序输出:

ONE :: 1
ONE :: 2
ONE :: 3

TWO :: 1
TWO :: 2
TWO :: 3

在评论中把您的问题交给我。

学习愉快!