2、synchronized

本文详细讲解了Java中`synchronized`关键字的使用,包括它如何锁定对象而非代码,对象头的锁机制,静态方法和实例方法的区别,以及同步方法的并发调用。还涉及了锁的重入性和不同类型的锁(如偏向锁、自旋锁和重量级锁)在JDK中的实现。

synchronized   锁的是对象不是代码
对某个对象加锁

public class T{
	private int count = 10;
	private Object o = new Object();

	public void m(){
		synchronized(o){   	//任何线程要执行下面的代码,必须先拿到o的锁
			count--;
			system.out.println(Thread.cunrentThread().getName() + "count = " + count);
		}
	}
}

对象头64位 有两位实现锁

public class T{
    private int count = 10;
    public void m(){
        synchronized(this){       //任何线程要执行下面的代码,必须先拿到this的锁
            count--;
            system.out.println(Thread.cunrentThread().getName() + "count = " + count);
        }
    }
}
public class T{
	private int count = 10;
//任何线程要执行下面的代码,必须先拿到锁
	public synchronized void  m(){   	
			count--;
			system.out.println(Thread.cunrentThread().getName() + "count = " + count);
		}
}

static类型

public class T{
	private static int count = 10;
	public synchronized static void  m(){   	 //这里等同于synchronized (T.class)
			count--;
			system.out.println(Thread.cunrentThread().getName() + "count = " + count);
		}
	public static void  m(){   
		synchronized (T.class)	
			count--;
		}
}

synchronized既保证了原子性又保证了可见性 

public class T implements Runnable{
	private int count = 10;
	public /*synchronized*/ void run(){
		count --;
		System.out.println(count);
	}

	public static void main(String[] args){
		T t = new T();
		for(int i = 0; i<100; i++){
			new Thread( t, "THREAD" + i ).start();
		}

	}
}

同步方法和非同步方法是否可以同时调用   可以

public  class  T{
	public synchronized void m1(){
		System.out.println("m1 start...");
		try{
			Thread.sleep(10000);
		} catch(InterruptedException e) {
		 	e.printStackTrace();
		}
		System.out.println("m1 end");
	}

	public void m2(){
		try{
			Thread.sleep(5000);
		} catch(InterruptedException e) {
		 	e.printStackTrace();
		}
		System.out.println("m2");
	}

	public static void main(String[] args){
		T t = new T();
		/*new Thread(()->t.m1(),"t1").start();
		new Thread(()->t.m2(),"t2").start();*/
		new Thread(t::m1,"t1").start();
		new Thread(t::m2,"t2").start();
	}
}
m1 start...
m2
m1 end

模拟银行账户  对业务写方法加锁 对业务读方法不加锁 

public class Account {
	String name;
	double balance;

	public synchronized void set(String name, double balance) {
		this.name = name;

		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.balance = balance;
	}

	public /* synchronized */ double getBalance(String name) {
		return this.balance;
	}

	public static void main(String[] args) {
		Account a = new Account();
		new Thread(() -> a.set("zhangsan", 100.0)).start();

		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(a.getBalance("zhangsan"));

		try {
			TimeUnit.SECONDS.sleep(2);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(a.getBalance("zhangsan"));
	}
}

==
synchronized 可重入锁   必须指同一个线程里面
如果程序中出现异常 锁会被释放
==
synchronized 的底层实现:
JDK早期的时候       重量级      - OS
后来的改进
锁升级的概念:
    我就是厕所所长(一、二)
sync(Object)
markWord  记录这个线程ID  (偏向锁)
如果有线程争用:升级为 自旋锁   用户态  执行时间短(加锁代码)线程数少
10次之后   
升级为  重量级锁  - OS  申请资源加锁  内核态    执行时间长、线程数多  等待队列
==
synchronized(Object)
   “Object”不能用String常量 Integer Long
==
final Object o = new Object();
synchronized(o)
==

### Java `synchronized` 关键字的语法及使用 #### 1. 基础概念 `synchronized` 是 Java 中的关键字,主要用于实现线程间的同步控制。它能够确保多个线程在访问共享资源时不会发生冲突,同时还能保证内存可见性和顺序一致性。 #### 2. 使用场景 `synchronized` 可以作用于 **实例方法**、**静态方法** 和 **代码块** 上,分别对应不同的锁机制:对象锁和类锁。 --- #### 3. 实例方法上的 `synchronized` 当 `synchronized` 应用于实例方法时,表示该方法会被加锁保护,只有持有当前对象锁(instance lock)的线程可以进入此方法[^1]。 ```java public class Counter { private int count; public synchronized void increment() { // 对象锁 count++; } public synchronized int getCount() { // 对象锁 return count; } } ``` 上述代码中,`increment()` 方法和 `getCount()` 方法都被标记为 `synchronized`,这意味着任何线程如果要调用这两个方法之一,则必须先获得当前对象的锁。 --- #### 4. 静态方法上的 `synchronized` 当 `synchronized` 被应用于静态方法时,意味着该方法使用的锁是整个类的锁(class lock),而不是某个具体对象的锁[^2]。 ```java public class TicketCounter { private static int tickets = 10; public static synchronized void sellTicket() { // 类锁 if (tickets > 0) { System.out.println(Thread.currentThread().getName() + " sold ticket: " + tickets--); } else { System.out.println("No more tickets available."); } } } ``` 在这个例子中,无论有多少个线程尝试调用 `sellTicket()` 方法,它们都必须依次排队,因为这是基于类级别的锁定。 --- #### 5. 同步代码块 除了对整个方法加锁外,还可以仅针对特定代码片段进行同步处理。这通常通过显式指定一个锁对象来完成: ```java public class BankAccount { private double balance; private final Object lock = new Object(); public void deposit(double amount) { synchronized (lock) { // 显式的锁对象 balance += amount; System.out.println(Thread.currentThread().getName() + ": Deposited " + amount + ", Balance is now " + balance); } } public void withdraw(double amount) { synchronized (lock) { // 显式的锁对象 if (balance >= amount) { balance -= amount; System.out.println(Thread.currentThread().getName() + ": Withdrew " + amount + ", Balance is now " + balance); } else { System.out.println(Thread.currentThread().getName() + ": Insufficient funds"); } } } } ``` 这里定义了一个私有的 `lock` 对象作为同步锁,避免了直接依赖外部不可控的对象锁。 --- #### 6. 字节码层面分析 从 JVM 的角度来看,`synchronized` 方法会在编译后生成特殊的字节码指令。对于非静态的 `synchronized` 方法,其对应的字节码会带有 `ACC_SYNCHRONIZED` 标志位;而对于同步代码块,则会有 `monitorenter` 和 `monitorexit` 指令来管理锁的操作[^3]。 --- #### 7. 等待/通知机制 `synchronized` 还支持与 `wait()` 和 `notify()/notifyAll()` 结合使用,以便实现更复杂的线程间通信逻辑。例如,在生产者消费者模式下,可以通过这些 API 来协调不同线程的行为[^4]。 ```java public class Buffer { private String data; private boolean isEmpty = true; public synchronized void produce(String value) throws InterruptedException { while (!isEmpty) { wait(); // 如果缓冲区已满,则等待 } this.data = value; isEmpty = false; notifyAll(); } public synchronized String consume() throws InterruptedException { while (isEmpty) { wait(); // 如果缓冲区为空,则等待 } isEmpty = true; notifyAll(); return data; } } ``` 在此示例中,`produce()` 和 `consume()` 方法均被声明为 `synchronized`,并利用了条件变量来进行协作。 --- #### 8. 锁升级原理 需要注意的是,JDK 内部实现了多种优化策略,比如偏向锁、轻量级锁以及重量级锁之间的转换过程。这种动态调整有助于减少不必要的性能开销[^5]。 --- ### 总结 `synchronized` 提供了一种简单而强大的方式来解决多线程环境下的竞争问题。然而,由于它的独占性质可能会引发死锁或者降低并发效率,因此开发者应谨慎设计程序结构,并考虑引入更高阶的技术手段如 ReentrantLock 或 AQS 等替代方案。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值