🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # synchronized ## 同步代码块 同步代码块: 在代码块声明上 加上synchronized ~~~ synchronized (锁对象) { 可能会产生线程安全问题的代码 } ~~~ 同步代码块中的锁对象可以是任意的对象;但**多个线程时,要使用同一个锁对象才能够保证线程安全**。 在方法中,对可能出错的加上 ~~~ synchronized (lock){ } ~~~ 成员中定义 ~~~ //定义锁对象 Object lock = new Object(); ~~~ ### 案例 ~~~ package com.study; class MyThread implements Runnable { private int ticket = 100; @Override public void run() { for (int i = 0; i < 200; i++) { //同步代码块 synchronized (this) { if (this.ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " ---卖票--- " + this.ticket--); } } } } } public class HelloWorld { public static void main(String[] args) { MyThread mt = new MyThread(); new Thread(mt, "A线程").start(); new Thread(mt, "B线程").start(); } } ~~~ ## 同步方法 * 同步方法:在方法声明上加上synchronized ~~~ public synchronized void method(){ 可能会产生线程安全问题的代码 } ~~~ **同步方法中的锁对象是 this** * 静态同步方法: 在方法声明上加上static synchronized ~~~ public static synchronized void method(){ 可能会产生线程安全问题的代码 } ~~~ **静态同步方法中的锁对象是 类名.class** ### 案例 ~~~ package com.study; class MyThread implements Runnable { private int ticket = 100; @Override public void run() { for (int i = 0; i < 200; i++) { //调用同步方法 this.sale(); } } //同步方法 private synchronized void sale() { if (this.ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " ---卖票--- " + this.ticket--); } } } public class HelloWorld { public static void main(String[] args) { MyThread mt = new MyThread(); new Thread(mt, "A线程").start(); new Thread(mt, "B线程").start(); } } ~~~ ## synchronized的缺陷 synchronized是java中的一个关键字,也就是说是Java语言内置的特性。 如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况: 1. 获取锁的线程执行完了该代码块,然后线程释放对锁的占有; 2. **线程执行发生异常,此时JVM会让线程自动释放锁。** 例子1:   如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。   因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过Lock就可以办到。 例子2: 当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作会发生冲突现象,但是读操作和读操作不会发生冲突现象。   但是采用synchronized关键字来实现同步的话,就会导致一个问题: 如果多个线程都只是进行读操作,当一个线程在进行读操作时,其他线程只能等待无法进行读操作。   因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。   另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。   总的来说,也就是说Lock提供了比synchronized更多的功能。