目录
前言
在多线程编程中,正确处理并发访问是确保程序正确性的关键。对象锁(Object Lock)是Java中常用的同步机制之一,用于防止多个线程同时访问共享资源。本文将详细讨论对象锁的同步和异步,以及如何在实际应用中有效地使用它们。
一、什么是对象锁?
对象锁是基于对象实例的锁机制。在Java中,每个对象都有一个关联的监视器(monitor),当一个线程请求一个对象的锁时,它会尝试获得该对象的监视器。如果监视器被其他线程持有,则该线程进入阻塞状态,直到监视器被释放。
二、同步和异步
同步(Synchronous)意味着代码片段或方法在同一时间只能被一个线程执行。同步保证了多个线程对共享资源的互斥访问,从而避免数据不一致的问题。
异步(Asynchronous)意味着代码片段或方法可以被多个线程同时执行,不进行任何同步控制。这虽然提高了并行度,但也可能导致竞态条件和数据不一致的问题。
区别:同步是加了synchronized的,需要按顺序排队访问,而异步(加asynchronized/没有)是多个线程可以同时访问
三、 同步代码块和同步方法
在Java中,可以使用synchronized
关键字来实现同步。我们可以将synchronized
关键字用于方法或者代码块。
同步方法
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
注:
increment
和getCount
方法是同步方法,意味着在同一时刻只能有一个线程访问这些方法。
同步代码块
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
public int getCount() {
synchronized (lock) {
return count;
}
}
}
四、异步方法
异步方法没有任何同步控制,多个线程可以同时访问:
public class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
注:如果多个线程同时调用
increment
方法,可能会导致count
的值不准确,因为多个线程可能会同时读取和写入该变量。
五、Demo讲解
package com.ctb.demo;
/**
* 对象锁的同步和异步问题
*
* @author biao
*
* 2024年2月28日-下午2:08:32
*/
public class MyThraed3 {
/**
* 加锁synchronized
*/
public synchronized void method1() {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 未加synchronized
*/
public void method2() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
final MyThraed3 m = new MyThraed3();
/**
* t1线程先持有object对象的lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
* t1线程先持有object对象的lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步
*/
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
m.method1();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
m.method2();
}
},"t2");
t1.start();
t2.start();
}
}
/**
* 加synchronized
*/
public synchronized void method2() {
System.out.println(Thread.currentThread().getName());
}
注:注:在method2方法中未加synchronized,它则会同时打印(t1 t2),若加上锁,它打印t1后需等待3s再打印t2