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
在评论中把您的问题交给我。
学习愉快!