互斥锁

举报
荞慧子 发表于 2022/12/31 19:48:44 2022/12/31
【摘要】 互斥锁基本介绍(1)Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。(2)每个对象都对应一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。(3)关键字synchronized用来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能有一个线程访问。(4)同步的局限性:导致程序的执行效率要降低。(5)同步方法...

互斥锁

基本介绍

(1)Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。

(2)每个对象都对应一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访

问该对象。

(3)关键字synchronized用来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在

任一时刻只能有一个线程访问。

(4)同步的局限性:导致程序的执行效率要降低。

(5)同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)

(6)同步方法(静态的)的锁为当前类本身。

使用互斥锁来解决售票问题


public class SellTicket {
    public static void main(String[] args) {
        //测试
        // SellTicket01 sellTicket01 = new SellTicket01();
        // SellTicket01 sellTicket02 = new SellTicket01();
        // SellTicket01 sellTicket03 = new SellTicket01();
        
        // //这里我们会出现超卖.. 
        // sellTicket01.start();//启动售票线程
        // sellTicket02.start();//启动售票线程
        // sellTicket03.start();//启动售票线程
        // System.out.println("===使用实现接口方式来售票=====");
        // SellTicket02 sellTicket02 = new SellTicket02();
        
        // new Thread(sellTicket02).start();//第 1 个线程-窗口
        // new Thread(sellTicket02).start();//第 2 个线程-窗口
        // new Thread(sellTicket02).start();//第 3 个线程-窗口
        
        //测试
        SellTicket03 sellTicket03 = new SellTicket03();
        new Thread(sellTicket03).start();//第 1 个线程-窗口
        new Thread(sellTicket03).start();//第 2 个线程-窗口
        new Thread(sellTicket03).start();//第 3 个线程-窗口
    }
}

//实现接口方式, 使用 synchronized 实现线程同步
class SellTicket03 implements Runnable {
    private int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;//控制 run 方法变量
    Object object = new Object();
    
    //同步方法(静态的)的锁为当前类本身
    //1. public synchronized static void m1() {} 锁是加在 SellTicket03.class
    //2. 如果在静态方法中,实现一个同步代码块. 
    /*
    synchronized (SellTicket03.class) {
        System.out.println("m2");
    }
    */
    
    public synchronized static void m1() {
    }
    public static void m2() {
        synchronized (SellTicket03.class) {
            System.out.println("m2");
        }
    }

    //1. public synchronized void sell() {} 就是一个同步方法
    //2. 这时锁在 this 对象
    //3. 也可以在代码块上写 synchronize ,同步代码块, 互斥锁还是在 this 对象
    public /*synchronized*/ void sell() { //同步方法, 在同一时刻, 只能有一个线程来执行sell方法
        synchronized (/*this*/ object) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }
            //休眠 50 毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数=" + (--ticketNum));//1 - 0 - -1 - -2
        }
    }
    @Override
    public void run() {
        while (loop) {
            sell();//sell 方法是一种同步方法
        }
    }
}

//使用 Thread 方式
// new SellTicket01().start()
// new SellTicket01().start();
class SellTicket01 extends Thread {
    private static int ticketNum = 100;//让多个线程共享 ticketNum
    // public void m1() {
        // synchronized (this) {
            // System.out.println("hello");
        // }
    // }

    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }
            //休眠 50 毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数=" + (--ticketNum));
        }
    }
}
    
    //实现接口方式
class SellTicket02 implements Runnable {
    private int ticketNum = 100;//让多个线程共享 ticketNum
    @Override
    public void run() {
        while (true) {
            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                break;
            }
            //休眠 50 毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票" + " 剩余票数=" + (--ticketNum));//1 - 0 - -1 - -2
        }
    }
}

注意事项和细节

(1)同步方法如果没有使用static修饰:默认锁对象为this

(2)如果方法使用static修饰,默认锁对象:当前类.class

(3)实现的落地步骤:

1)需要先分析上锁的代码

2)选择同步代码块或同步方法

3)要求多个线程的锁对象为同一个即可

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。