前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Java]Java多线程数据安全(同步线程的方法)

[Java]Java多线程数据安全(同步线程的方法)

作者头像
祥知道
发布2020-03-10 14:50:44
4420
发布2020-03-10 14:50:44
举报
文章被收录于专栏:祥的专栏祥的专栏

原创文章,欢迎转载。转载请注明:转载自 祥的博客 原文链接:http://blog.csdn.net/humanking7/article/details/43541387

预备知识


Thread.yield():
代码语言:javascript
复制
API中解释: 暂停当前正在执行的线程对象,并执行其他线程。

注意:这里的其他也包含当前线程,即,当前线程也能够再次抢占CPU。

Thread.sleep(long millis):
代码语言:javascript
复制
 API解释:使当前线程暂停millis所指定的毫秒,转到执行其它线程。

不使用关键字synchronized(容易出错)


Java源代码
代码语言:javascript
复制
public class MyRunnable implements Runnable{

    private int num = 100;            

    @Override
    public void run() {
        while(true){
            System.out.println(Thread.currentThread().getName() + "@: " + this.num);
            this.num --;
            Thread.yield();   //为了更容易产生错误
            if(this.num < 0){
                break;
            }
        }  
    }

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();

        Thread th1 = new Thread(myRunnable,"线程A");    
        Thread th2 = new Thread(myRunnable,"线程B");    

        th1.start();
        th2.start();
    }
}
运行结果
.\java1.png
.\java1.png

上述错误就是典型的多线程访问数据错误。

分析

我来试着分析一下产生这个错误的原因:

  1. 刚开始线程B执行,但是在马上要打印到屏幕的时候(执行到这个代码中System.out.println(Thread.currentThread().getName() + "@: " + this.num);),被线程A抢到CPU了;
  2. 此时num还没没有执行自减操作,即num == 100
  3. 这个时候CPU一直被线程A占用着,一直运行,到打印出线程A@:94时,线程A抢到了CPU
  4. 线程B打印出线程B@:100,其实此时num == 93,只是原来把100数据已经写进了程序的堆栈中;
  5. 接着线程B继续执行代码,num自减,即num == 92
  6. 下面就是线程B愉快的执行代码了。

使用synchronized同步代码块


Java源代码
代码语言:javascript
复制
public class MyRunnable implements Runnable{

    private int num = 100;            

    @Override
    public void run() {
        while(true){
            System.out.println(Thread.currentThread().getName());
            synchronized(this){
                System.out.println(Thread.currentThread().getName() + "@: " + this.num);
                this.num --;
                Thread.yield();//为了更容易产生错误
                if(this.num < 0){
                    break;
                }
            }           
        }  
    }

    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();

        Thread th1 = new Thread(myRunnable,"线程A");    
        Thread th2 = new Thread(myRunnable,"线程B");    

        th1.start();
        th2.start();
    }
}
运行结果
正确
正确
分析

我来分析一下用红框标记结果的执行流程。

分析之前先设定代码System.out.println(Thread.currentThread().getName());代码1,设定代码System.out.println(Thread.currentThread().getName() + "@: " + this.num);代码2

  1. 线程B获取CPU,执行了代码1
  2. 线程B进入同步代码块,执行了代码2,但还没有退出同步代码块的时候,线程A抢到了CPU;
  3. 线程A执行了代码1,但是无法进入同步代码块,只能等待,这时候线程B获得了CPU,继续执行代码,执行到了代码1时,线程A又获得了CPU;
  4. 线程A接着刚才继续执行,此时因为线程B已经不在同步代码块中,所以线程A就可以进入同步代码块,执行代码2

真是绕啊,分析完毕,不知道有没有什么错误,还望大家批评指正,共同进步。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 预备知识
    • Thread.yield():
      • Thread.sleep(long millis):
      • 不使用关键字synchronized(容易出错)
        • Java源代码
          • 运行结果
            • 分析
            • 使用synchronized同步代码块
              • Java源代码
                • 运行结果
                  • 分析
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档