搜公众号
推荐 原创 视频 Java开发 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库
Lambda在线 > 我的编程笔记 > Java基础之线程安全

Java基础之线程安全

我的编程笔记 2019-02-11
举报

回顾

在上一篇 ,我们讲解了多线程的实现,运行起来似乎也没什么问题,但是我们若加一段代码

class Window implements Runnable{//实现接口
    int ticket=100;
    @Override
    public void run() {
        while (true){
            if(ticket>0){
                try {
                    Thread.currentThread().sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"售票:票号为:"+ ticket--);
            }else{
                break;
            }
        }
    }
}
Window w=new Window();
        Thread t1=new Thread(w);
        Thread t2=new Thread(w);
        Thread t3=new Thread(w);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t1.start();
        t2.start();

相比与上一篇我们的代码里多了

Thread.currentThread().sleep(10);

sleep()方法使得当前线程阻塞10毫秒,我们看代码运行效果


票卖超了,怎么回事?按代码逻辑来看,好像并没什么问题?

这就是存在 线程不安全

问题分析

那么我们分析下如何出现的这个现象?
我们假设有两个卖票线程:线程A和线程B ,此时余票还有1张,看下图

Java基础之线程安全

Java基础之线程安全

文字解释下,当ticket=1时,线程A进入if判断内,接着线程A进入sleep状态,紧接着线程B获得cpu执行权开始执行,
此时ticket=1,进入if判断内 也开始sleep,然后线程A的sleep结束 恢复,开始执行,并把ticket—,此时ticket=0,然后线程B恢复,
打印tickect为0,ticket再次-1.变成了-1.
这就时三个窗口同时卖票,票卖超的原因,也称线程不安全。

线程安全

上面我们分析了导致线程不安全出现的原因?那怎么解决呢?

  • 我们希望一个线程操作共享数据结束以后,其他的线程才有机会参与共享数据的操作。

线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

用java代码来实现,主要有两种方法:

线程的同步机制

方法一 :同步代码块

格式如下 使用synchronized关键字

synchronized(同步监视器){
    //需要被同步的代码块(操作共享数据的代码块)
}

以上同步监视器 又称为“锁”,锁需要唯一,代码如下

class Window implements Runnable{//实现接口
    int ticket=100;
    @Override
    public void run() {
        while (true){
            synchronized (this){
                if(ticket>0){
                    try {
                        Thread.currentThread().sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"售票:票号为:"+ ticket--);
                }
            }
        }
    }
}

执行后如下,正常!
Java基础之线程安全

方法二 :同步方法

将操作共享数据的代码 提取到一个方法内 然后用synchronized 修饰

synchronized void show(){
    //操作共享数据的代码
}

修改卖票程序用同步方法实现如下:

class Window implements Runnable{//实现接口
    int ticket=100;
    public synchronized void show(){
        if(ticket>0){
            try {
                Thread.currentThread().sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"售票:票号为:"+ ticket--);
        }
    }
    @Override
    public  void run() {
        while (true){
            this.show();
        }
    }
}

注意在同步方法实现中 锁默认为this 也需要唯一,
我们用图解释下线程安全下两个线程如何操作共享数据的:

由上图我们知道,一旦遇到操作共享数据时,线程总是同步执行的。

总结

  • 遇到多个线程操作共享数据时就会出现线程不安全问题

  • 同步方法或者同步代码块 都是为了让线程同步执行

  • 同步方法和同步代码块都需要一个对象 作为锁,这个锁要确保唯一性

喜欢本文的朋友们,欢迎长按下图关注订阅号”我的编程笔记”,收看更多精彩内容~~

版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《Java基础之线程安全》的版权归原作者「我的编程笔记」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注我的编程笔记微信公众号

我的编程笔记微信公众号:program-notes

我的编程笔记

手机扫描上方二维码即可关注我的编程笔记微信公众号

我的编程笔记最新文章

精品公众号随机推荐

举报