我们来详细讲解一下 Java 对象锁和类锁。
什么是对象锁?
在 Java 中,每一个对象都有一个锁,也就是监视器锁(Monitor Lock)。当一个线程访问某个对象的 synchronized 方法或 synchronized 块时,这个线程会试图获得这个对象的锁。获得对象锁后,这个线程才能进入 synchronized 方法或 synchronized 块中执行代码。其他线程必须等待锁的释放才能继续执行。
一个对象锁只保护一个对象的同步方法或同步块。如果一个对象有多个同步方法,每个方法都可以被独立执行,因为每个方法都有自己的对象锁。如果一个线程正在执行某个对象的同步方法,其他线程可以访问该对象的非同步方法,因为这些非同步方法没有竞争这个对象锁。
下面是一个简单的示例代码,通过 synchronized 关键字实现了线程之间的同步:
public class MyThread extends Thread {
private String threadName;
private Object object;
public MyThread(String name, Object obj) {
threadName = name;
object = obj;
}
public void run() {
synchronized(object) {
System.out.println(threadName + " has acquired the object lock.");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println(threadName + " is releasing the object lock.");
}
}
public static void main(String[] args) {
Object obj = new Object();
MyThread t1 = new MyThread("Thread 1", obj);
MyThread t2 = new MyThread("Thread 2", obj);
t1.start();
t2.start();
}
}
运行上面的代码,你会发现 Thread 1 和 Thread 2 交替获得和释放了 obj 这个对象的锁。
什么是类锁?
除了对象锁以外,Java 还有一种锁叫做类锁(Class Lock)。当一个线程访问某个类的 synchronized 静态方法或 synchronized(classname) 代码块时,这个线程会获得这个类的 Class 对象的锁。类锁只有一个,因此多个线程访问类的 synchronized 静态方法或 synchronized(classname) 代码块时会相互竞争,而不同的类的 synchronized 静态方法或 synchronized(不同的Class对象) 代码块之间没有竞争关系。
和对象锁一样,类锁也是可重入的,也就是说一个线程已经获得了某个类的锁,那么它可以重复获得该锁,而不用重新等待锁的释放。
下面是一个示例代码,演示了如何使用类锁:
public class ThreadSafeCounter {
private static int count = 0;
public static synchronized void increment() {
System.out.println(Thread.currentThread().getName() + " is running increment().");
int temp = count;
temp++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count = temp;
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
ThreadSafeCounter.increment();
});
Thread t2 = new Thread(() -> {
ThreadSafeCounter.increment();
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("The final count is " + count);
}
}
在上面的示例代码中,我们定义了一个静态方法 increment(),使用 synchronized 关键字修饰,实现了对 count 变量的线程安全访问。在 main 方法中,我们启动了两个线程对 count 变量进行自增操作,由于 increment() 方法使用的是类锁,所以两个线程会相互竞争,保证了对 count 变量的线程安全访问。
通过这两个示例,我们可以更好地理解对象锁和类锁在 Java 中的应用。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解java 对象锁与类锁 - Python技术站