文章目录
一、基本使用
synchronized是Java并发编程中的同步机制关键字,它能保证同一个时刻只有一条线程能够执行被关键字修饰的代码,其他线程就会在队列中进行等待,等待这条线程执行完毕后,下一条线程才能对执行这段代码。
synchronized的3种使用方式:
- 修饰实例方法:作用于当前实例加锁
- 修饰静态方法:作用于当前类对象加锁
- 修饰代码块:指定加锁对象,进入同步代码块前要获得给定对象的锁
1.1、对象锁
类加载后,我们可以new出很多个实例对象,每个实例对象在JVM中都有自己的引用地址和堆内存空间,这些实例都是独立的个体,所以在实例上加锁和其他的实例肯定没有关系,不同实例的锁互不影响。
当一个对象中有同步方法或者同步代码块时,线程调用此对象进入同步区域前,就必须获得对象锁。如果此对象的对象锁被其他调用者占用,则进入阻塞队列,等待此锁被释放(同步块正常返回或者抛异常终止,由JVM自动释放对象锁)。
注意:使用对象锁时,当一个线程访问一个带synchronized的方法时,由于对象锁的存在,该对象中所有加synchronized的方法都不能被访问。
public class ObjectLock {
public static void main(String[] args) {
TestObjectLock objectLock = new TestObjectLock();
new Thread(objectLock::test1).start();
new Thread(objectLock::test2).start();
}
static class TestObjectLock {
public synchronized void test1() {
System.out.println("test1..." + System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void test2() {
System.out.println("test2..." + System.currentTimeMillis());
}
}
}
1.2、类锁
每个class其中的静态方法和静态变量在JVM中只会加载和初始化一份,所以当静态方法被加上synchronized关键字后,此类的所有的实例化对象在调用该方法时,都会共用同一把锁,称之为类锁。
不管多少对象都共用同一把锁,都将是同步执行,一个线程执行结束,其他的才能够调用同步的部分,不同的类锁互不影响。
public class ClassLock {
public static void main(String[] args) {
new Thread(TestClassLock::test1).start();
TestClassLock classLock = new TestClassLock();
new Thread(classLock::test2).start();
}
static class TestClassLock {
public static synchronized void test1() {
System.out.println("test1..." + System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void test2() {