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

多线程的锁有: 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();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值