Java synchronized基础用法

本文深入探讨Java中的synchronized关键字,解析其实现对象锁、锁重入、异常释放锁等特性,对比静态与非静态方法的锁机制,揭示内部类与静态内部类的同步规则,强调避免死锁的重要性,并讲解volatile关键字的作用及其局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法当作锁。

2. 关键字synchronized拥有锁重入的功能
在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的
在一个synchronized方法/块内部调用本类的其他synchronized方法/块时,是永远可以得到锁的

public class Service {
	synchronized public void service1() {
		...
		service2();
	}
	synchronized public void service2(){}
}

当存在父子类继承关系时,子类是完全可以通过可重入锁调用父类的同步方法的

3. 当一个线程执行的代码出现异常时,其所持有的锁会自动释放

4. synchronized 不会由父类继承给子类

5. synchronized 同步语句块

public void service() {
	...
	synchronized(x) {
		...
	}
	...
}

用synchronized 声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间任务,那么B线程则必须等待比较长的时间。
synchronized方法是对当前对象进行加锁,而synchronized代码块是对某一个对象进行加锁
可以把synchronized 只加在方法内需要同步的公共资源修改上,让其他不需要同步的代码块可以被多个线程同时执行,节约时间

synchronized的对象监视器不同,会异步调用。测试:

class SyncBlock {
    private String anyString = new String();

    public void a() {
        try {
            synchronized (anyString) {
                System.out.println(Thread.currentThread().getName() + ":begin");
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName() + ":end");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    synchronized public void b() {
        System.out.println(Thread.currentThread().getName() + ":begin");
        System.out.println(anyString + "。");
        System.out.println(Thread.currentThread().getName() + ":end");
    }
}

public static void main(String[] args) throws InterruptedException {
        SyncBlock syncBlock = new SyncBlock();
        Thread t1 = new Thread() {
            @Override
            public void run() {
                syncBlock.a();
            }
        };

        Thread t2 = new Thread() {
            @Override
            public void run() {
                syncBlock.b();
            }
        };

        t1.start();
        t2.start();
    }
}
//Thread-1:begin
//Thread-2:begin
//。
//Thread-2:end
//Thread-1:end

6. 静态同步synchronized方法 与 synchronized(class)代码块

synchronized 加在静态方法上,是对当前的Class类进行持锁,sychronized(class)也是同样的效果
synchronized加在静态方法和非静态方法上,持有锁的对象是不同的,是异步调用
对Class类加锁可以对类的所有实例起作用,同一个类的不同实例对象间调用这类方法是同步的

7. 要避免调用双方互持有对方锁的情况,互相等待对方释放锁会出现死锁

8. 内部类与静态内部类

内部类中同步方法规则和普通类一样
静态内部类 测试:

public class OutClass {
	static class InnerClass1{
		public void method1(InnerClass2 class2) {
			...
			synchronized(class2) {
				...
			}
			...
		}
		public void method2() {
			...
		}
	}
	
	static class InnerClass2{
		public void method1() {
			...
		}
	}
}
····························································
InnerClass1 in1;
InnerClass2 in2;
线程1 in1.method1(in2);
线程2 in1.method();
线程3 in2.method1();
//线程1和线程3同步,和线程2异步

9. 对于锁对象,只要对象不变,即使对象的属性改变,运行的结果还是同步的

10. volatile关键字

主要作用是使变量在多个线程间可见
它会强制从公共栈中取得变量的值,而不是从线程私有数据栈中取得变量的值
只能修饰变量
volatile不支持原子性:

  • 对于volatile修饰的变量,JVM虚拟机只是保证从主内存加载到线程工作内存的值是最新的。在加载后这个值可能被其他线程改了,这时线程工作内存的值已经加载,不会变化了,也就是私有内存和公共内存中的变量不同步

原子类型可以在没有锁的情况下做到线程安全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值