多线程基础讲解五: synchronized使用

    技术2025-11-09  6

    多线程的锁有: synchronized 和 jdk1.5的Lock

     

    先说synchronized的各种用法:

    1. 使用任意同一对象做锁  (一定要是同一对象)

    2. 使用this做锁

    3. class字节码文件做锁

    4. 静态同步代码块做锁    (原理其实就是:class字节码文件做锁)

    5.非静态同步代码块做锁 (原理其实就是:使用this做锁)

     

    任意对象做锁例子:

    /** * @author: wangqinmin * @date : 2020/7/3 * @description: 仰天大笑出门去,我辈岂是蓬蒿人 */ public class TicketRunnable implements Runnable { /** * 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。 */ int tickets = 100; private Object obj = new Object(); public void run() { while (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } sale(); } } public void sale() { /** * 使用任意、同一对象做锁 */ synchronized (obj) { /** * 最后判断一下,还是因为有线程安全的问题。 * * 最后一张票卖完后,tickets = 0,但是这时候,最后一个等待的线程刚刚就就进来了,所以会得到100 - 0 + 1 ,结果为101的票,所以在这里判断一下。 * 还有一个办法,就是在 while (tickets > 0) 之前就加 synchronized。 * 但是使用synchronized最好包裹的代码很少,所以就这样写了。 * 又如果在while那里就包裹了,多半这个代码直接就一个线程执行完了。 */ if (tickets > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票"); tickets--; } } } }

     

    this做锁的例子:

    /** * @author: wangqinmin * @date : 2020/7/3 * @description: 仰天大笑出门去,我辈岂是蓬蒿人 */ public class TicketRunnable implements Runnable { /** * 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。 */ int tickets = 100; public void run() { while (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } sale(); } } public void sale() { /** * this做锁 */ synchronized (this) { /** * 最后判断一下,还是因为有线程安全的问题。 * * 最后一张票卖完后,tickets = 0,但是这时候,最后一个等待的线程刚刚就就进来了,所以会得到100 - 0 + 1 ,结果为101的票,所以在这里判断一下。 * 还有一个办法,就是在 while (tickets > 0) 之前就加 synchronized。 * 但是使用synchronized最好包裹的代码很少,所以就这样写了。 * 又如果在while那里就包裹了,多半这个代码直接就一个线程执行完了。 */ if (tickets > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票"); tickets--; } } } }

     

    class字节码文件做锁的例子:

    /** * @author: wangqinmin * @date : 2020/7/3 * @description: 仰天大笑出门去,我辈岂是蓬蒿人 */ public class TicketRunnable implements Runnable { /** * 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。 */ int tickets = 100; private Object obj = new Object(); public void run() { while (tickets > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } sale(); } } public void sale() { /** * class文件做锁 */ synchronized (TicketRunnable.class) { /** * 最后判断一下,还是因为有线程安全的问题。 * * 最后一张票卖完后,tickets = 0,但是这时候,最后一个等待的线程刚刚就就进来了,所以会得到100 - 0 + 1 ,结果为101的票,所以在这里判断一下。 * 还有一个办法,就是在 while (tickets > 0) 之前就加 synchronized。 * 但是使用synchronized最好包裹的代码很少,所以就这样写了。 * 又如果在while那里就包裹了,多半这个代码直接就一个线程执行完了。 */ if (tickets > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票"); tickets--; } } } }

     

     

    静态同步代码块做锁: (并证明原理为 字节码文件为锁)

    /** * @author: wangqinmin * @date : 2020/7/3 * @description: 仰天大笑出门去,我辈岂是蓬蒿人 */ public class TicketRunnable implements Runnable { /** * 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。 * <p> * 使用静态变量 */ private static int tickets = 100; private Object obj = new Object(); public void run() { while (tickets > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } if (tickets % 2 != 0) { synchronized (TicketRunnable.class) { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票"); tickets--; } } } else { sale(); } } } /** * 定义静态同步代码块 * 在方法上,加上 static 和 synchronized。 * <p> * 原理: 这个其实就是使用的字节码文件做锁。 * <p> * 怎么证明呢 ? 可以写两个线程,一个使用字节码文件做锁,一个使用静态同步代码块,如果完成了同步功能,就证明静态同步代码快使用的是 字节码文件做锁。 * <p> * 在工作中,不推荐使用静态同步锁,因为静态方法不会被回收。 * 建议使用 非静态同步代码块做锁; */ public static synchronized void sale() { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票"); tickets--; } } }

     

     

    非静态同步代码块做锁:(并证明原理为: this做锁)

    /** * @author: wangqinmin * @date : 2020/7/3 * @description: 仰天大笑出门去,我辈岂是蓬蒿人 */ public class TicketRunnable implements Runnable { /** * 需求现在有100张火车票,有两个窗口同时抢火车票,请使用多线程模拟抢票效果。 * <p> * 使用静态变量 */ private int tickets = 100; private Object obj = new Object(); public void run() { while (tickets > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } /** * 使用判断,证明非静态同步代码快使用的是this锁 */ if (tickets % 2 != 0) { synchronized (this) { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票"); tickets--; } } } else { sale(); } } } /** * 定义非静态同步代码块 * 在方法上,加上 synchronized。 * <p> * 原理: 这个其实就是使用的this锁。 * <p> * 怎么证明呢 ? 可以写两个线程,一个使用this锁,一个使用非静态同步代码块,如果完成了同步功能,就证明非静态同步代码快使用的是this锁。 */ public synchronized void sale() { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + ",出售第" + (100 - tickets + 1) + "票"); tickets--; } } }

     

     

    上面都是各种做锁的例子, 这里是创建多线程,并调用:

    /** * @author: wangqinmin * @date : 2020/7/3 * @description: 仰天大笑出门去,我辈岂是蓬蒿人 */ public class Test { public static void main(String[] args) { TicketRunnable ticket = new TicketRunnable(); Thread t1 = new Thread(ticket, "窗口1"); Thread t2 = new Thread(ticket, "窗口2"); t1.start(); t2.start(); } }

     

    Processed: 0.031, SQL: 9