栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

线程安全问题。文字为主,来源于马士兵赵珊珊老师,代码为辅,自学用,谨慎借鉴,有错误请指正

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

线程安全问题。文字为主,来源于马士兵赵珊珊老师,代码为辅,自学用,谨慎借鉴,有错误请指正

在《程序,进程,线程和创建方法》的博客中,第二个经典火车票的案例有问题,是因为线程不安全的原因:多个线程在争抢资源的过程中,很可能会导致资源共享--->一个线程还没执行完,另一个线程就参与进来了开始争抢资源。

如何解决:加个锁

形象理解:去上厕所,人进去之后锁上门,外面的人无论多着急都必须等着锁打开里面的人出来后才能进去

public class TicketThreadSyn implements Runnable{
    static int ticketNumber = 10;

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            // 把具有安全隐患的代码锁住就行了,锁多了会效率低
            synchronized (this) {
                if (ticketNumber > 0) {
                    System.out.println("我在" + Thread.currentThread().getName() + "买到了第" + ticketNumber-- + "张票");
                }
            }
        }
    }
}
    public static void main(String[] args) {
        TicketThreadSyn tts = new TicketThreadSyn();
        Thread tt1 = new Thread(tts,"窗口1");
        tt1.start();
        Thread tt2 = new Thread(tts,"窗口2");
        tt2.start();
        Thread tt3 = new Thread(tts,"窗口3");
        tt3.start();
    }

成功解决

第一个经典火车案例加锁:

形象记忆:在古代上厕所没有锁这个东西,人们会在厕所前面放着红色橙色两个不同颜色水杯,谁上厕所就会把其中一个水杯放到厕所门口。然而其中有的人只认识其中一种颜色的水杯。当另一种颜色的水杯放在门口的时候,这类人因为不认识,所以仍然会去上厕所,这就造成了抢厕所的问题。所以为了解决,必须只能有一个颜色的水杯并且所有人都认识

public class TicketThreadSynThread extends Thread{
    static int ticketNumber = 50;

    public TicketThreadSynThread() { }

    public TicketThreadSynThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            synchronized (TicketThreadSynThread.class){// 无论多少个对象,都认识这个类的字节码
                if(ticketNumber > 0){
                    System.out.println("我在" + this.getName() + "买到了第" + ticketNumber-- +"张票");
                }
            }
        }
    }
}
    public static void main(String[] args) {
        TicketThreadSynThread tt1 = new TicketThreadSynThread("窗口1");
        tt1.start();
        TicketThreadSynThread tt2 = new TicketThreadSynThread("窗口2");
        tt2.start();
        TicketThreadSynThread tt3 = new TicketThreadSynThread("窗口3");
        tt3.start();
    }

同步监视器总结:

总结一:认识同步监视器:synchronized(同步监视器){ }

        1.必须是引用数据类型

        2.可以创建一个专门的同步监视器,没有任何业务含义

        3.一般使用共享资源做同步监视器即可

        4.在同步代码块中不能改变同步监视器对象的引用

        5.尽量不要用String和包装了Integer做同步监视器

        6.建议使用final修饰同步监视器

总结二:同步代码块的执行过程

        1.第一个线程来到同步代码块,发现同步监视器open状态,需要close然后执行其中代码

        2.第一个线程执行过程中,发生了线程切换(阻塞 就绪),第一个线程是去了CPU,但是没有开锁open

        3.第二个线程获取了CPU,来到同步代码块,发现同步监视器close状态,无法执行其中的代码,第二个线程也进入阻塞状态

        4.第一个线程再次获取CPU,接着执行后续的代码;同步代码块执行完毕,释放锁open

        5.第二个线程也再次获取CPU,来到了同步代码块,发现同步监视器open状态,拿到所并且上锁,由阻塞状态进入就绪状态,在进入运行状态,重复第一个线程的处理过程(加锁)

        强调:同步代码块中能发生CPU切换吗?能!但后续的被执行线程也无法执行同步代码块,因为锁仍旧是close

总结三:

        1.多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的代码块,其他线程无法访问其中的任何一个代码块

        2.多个代码块使用了同一个同步监视器(锁),锁住一个代码块的同时,也锁住所有使用该锁的代码块,但是没有锁住使用其他同步监视器的代码块,其他线程有机会访问其他同步监视器的代码块

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/572180.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号