Java内置锁简单用法

mac2026-09-30  3

概念及解释

Java的内置锁:每个Java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

重入:某个线程请求一个由其他线程持有的锁时,发出请求的线程会阻塞。如果线程试图获取一个已经由它自己持有的锁,那么他发出的请求就会成功。

1.Java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,知道线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

2.Java内置锁的区分:对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。一个对象对应一个对象锁一个类只有一个类锁。类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的

用法

public class SynchronizedTest { private static int value = 0; private final Object object = new Object(); /** * 线程不安全的 * * @return * @throws Exception */ public int getValue() throws Exception { value++; Thread.sleep(100); return value; } /** * 线程安全的 * 非静态方法加锁 * 方法锁(对象锁的一种) * @return * @throws InterruptedException */ public synchronized int getValue1() throws InterruptedException { value++; Thread.sleep(100); return value; } /** * 线程安全的 * 静态方法加锁 * 类锁 * * @return * @throws InterruptedException */ public static synchronized int getValue2() throws InterruptedException { value++; Thread.sleep(100); return value; } /** * 线程安全的 * 对象锁 * @return * @throws InterruptedException */ public int getValue3() throws InterruptedException { synchronized (object) { value++; Thread.sleep(100); return value; } } /** * 线程安全的 * 类锁 * @return * @throws InterruptedException */ public int getValue4() throws InterruptedException { synchronized (Object.class) { value++; Thread.sleep(100); return value; } } public static void main(String[] args) { final SynchronizedTest synchronizedTest = new SynchronizedTest(); //创建了一个最大容量为5的线程池 ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 1; i < 10; i++) { executorService.execute(new Runnable() { @Override public void run() { try { System.out.println(synchronizedTest.getValue());//调用非安全的方法 //System.out.println(synchronizedTest.getValue1());//调用加了方法锁的方法 //System.out.println(synchronizedTest.getValue2());//调用加了类锁的方法 //System.out.println(synchronizedTest.getValue3());//调用对象锁代码块的方法 //System.out.println(synchronizedTest.getValue4());//调用类锁代码块的方法 } catch (Exception e) { e.printStackTrace(); } } }); } executorService.shutdown(); } }

测试结果

非线程安全的方法getValue运行结果

其他线程安全的方法运行结果

注意事项

1.一个类的对象锁和另一个类的对象锁是没有关联的,当一个线程获得A类的对象锁时,它同时也可以获得B类的对象锁。

2.一个类中带对象锁的方法和不带锁的方法,可以异步执行,不干扰,不需要等待。

3.一个类中,如果set()方法加了对象锁,get()方法不加对象锁,容易发生数据脏读。可以用类锁或者set、get都加对象锁,解决。

4.同一个类中,多个锁方法相互调用,线程安全。

5.父子类中,锁方法相互调用,线程安全。

6.锁重入,在继承关系中适用。

7.锁方法发生异常时,会自动释放锁。程序继续执行,如果没有响应的处理,会发生业务逻辑的漏洞或者混乱。多见批处理、消息队列等。

8.类中的object成员变量加锁,为任意对象锁。

9.String常量值加锁,容易发生死锁。

10.如果你在一个对象锁方法中,对这个锁对象的引用做了修改,则表示释放了锁对象。如重新new object(),赋值给这个锁对象。但是锁对象的属性或值发生改变,并不发生锁的释放。

最新回复(0)