Java同步块
Java同步块语法
编写同步块的一般语法如下。
这里的 lockObject 是对一个对象的引用,该对象的锁与同步语句表示的监视器相关联。
synchronized( lockObject )
{
// 同步语句
}
内部工作原理
当一个线程想要在同步块内执行同步语句时,它必须在 lockObject的监视器上获取锁。
一次,只有一个线程可以获取锁对象的监视器。
所以所有其他线程必须等到这个线程,当前获取锁,完成它的执行。
这样,synchronized 关键字保证一次只有一个线程执行同步块语句,从而防止多个线程破坏块内的共享数据。
请记住,如果线程进入睡眠状态(使用 sleep()方法),那么它不会释放锁。
在这个休眠时间,没有线程会执行同步块语句。
如果'synchronized (lock)'中使用的锁对象为null,则Java 同步将抛出NullPointerException。
Java 同步块示例
请注意,printNumbers() 方法中的代码位于 synchronized 块中。
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();
// 第一个线程
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
Java同步方法
Java同步方法语法
编写同步方法的一般语法如下。
这里的 lockObject 是对一个对象的引用,该对象的锁与同步语句表示的监视器相关联。
<access modifier> synchronized method( parameters )
{
// 同步代码
}
Java同步方法内部工作原理
与同步块类似,线程必须使用同步方法获取关联监视器对象上的锁。
在同步方法的情况下,锁对象是
- '.class' 对象 - 如果方法是静态的。
- 'this' 对象 - 如果该方法不是静态的。“this”指的是对调用同步方法的当前对象的引用。
Java synchronized 关键字本质上是可重入的,这意味着如果一个同步方法调用另一个需要相同锁的同步方法,那么当前持有锁的线程可以在不获取锁的情况下进入该方法。
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
Java synchronized 关键字将块或者方法标记为临界区。
临界区是一次只有一个线程正在执行的地方,并且该线程持有同步部分的锁。
synchronized 关键字有助于编写应用程序的并发部分,以保护此块中的共享资源。
synchronized关键字可用于
- 一个代码块
- 一个方法
