ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java多线程5:线程同步机制(synchronized)

2022-01-22 23:02:39  阅读:136  来源: 互联网

标签:java synchronized Thread num 线程 new 多线程 tread


线程同步

在单线程程序中,后面的线程只能到前面的线程执行完毕才能执行,这不会出现线程抢占问题。但是在多任务的操作系统中,不同优先级的线程抢占CPU资源,这会造成线程共享资源出现资源冲突的问题

我们来引入一个场景:秒杀我们都经常见到过。假如有2个人抢一台手机,势必会造成有一个能抢到,有一个抢不到。假如A运气比较好,抢到了,那么手机数量就会-1,进而变成0,这时候B再来秒杀手机时,程序询问手机数量发现为0,进而反馈:运气真不好,手机被抢走了。

但是如果没有线程同步,当A购买了手机,此时应该手机要减一,但是线程A并没有修改。B也打算下单,程序询问手机数量发现手机还是1(按理来说应该是0),也下单成功。此时就会造成,明明只有一台手机,但是有两个人下单成功的尴尬局面。

因此线程同步是个非常重要的问题:场景也有很多(火车票售卖、淘宝库存、排号系统等等)

这种都必须要求,只有一个线程能访问线程共享资源(剩余票数,库存数,资源剩余),等他执行完毕,才允许其他线程访问

我们来通过买票问题来说明问题

一开始没有线程同步时

public class TreadSafe implements Runnable{

    int num=10;
    @Override
    public void run() {
        while (true){
            if(num>0){
                try {
                    Thread.sleep(100);
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("tickets:"+num--);
            } 
        }
    }
    public static void main(String [] args){
        TreadSafe tread =new TreadSafe();
        Thread t1=new Thread(tread);
        Thread t2=new Thread(tread);
        Thread t3=new Thread(tread);
        Thread t4=new Thread(tread);
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

到最后你会发现tickets

在这里插入图片描述

这就是各个线程没有同步的后果,线程1234都有各自的tickets数值,但互相没有同步,会恶意修改num值

那就会出现明明线程1拿走最后一张票了,线程2访问时发现自己的tickets并不是0,继续访问if{}

线程锁

既然问题出现了,那么就有解决问题的方法,那就是给共享资源(票数)上一道锁,当一个线程访问共享资源时,上一道锁,其他线程只能等待前面的线程执行完毕才可以访问。

synchronized关键字可以实现,是基于悲观锁设计的,被synchronized标注的代码块只允许一个线程能访问资源,其他线程等待前面的线程执行完才能进入。

synchronized有两种表示方法

一种是synchronized代码块;一种是synchronized方法

先看第一种

public class TreadSafe implements Runnable{

    int num=10;
    @Override
    public void run() {
        while (true){
            synchronized (""){
                if(num>0){
                    try {
                        Thread.sleep(100);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    System.out.println("tickets:"+num--);
                }
            }
        }
    }
    public static void main(String [] args){
        TreadSafe tread =new TreadSafe();
        Thread t1=new Thread(tread);
        Thread t2=new Thread(tread);
        Thread t3=new Thread(tread);
        Thread t4=new Thread(tread);
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}

我们在之前的例子 中while加入synchronized代码块

synchronized(object){
	//...
}

其实现原理就是,Object为一个任意对象,在每个对象里都有一个标志位(o or 1)。当一个线程访问该代码块时,会先访问对象的标志位,如果标志位为0,说明有其他线程在执行,就自己进入就绪状态直到标志位为1,才能进入该代码块执行,此时标志位又会从1变成0;该代码区又会称为临界区。

这样就能解决问题

在这里插入图片描述

还有一种就是synchronized方法,在前面加上synchronized修饰的方法

synchronized void f(){}

在之前的案例中创建一个类文件,在该类里定义同步方法

public synchronized void doit(){
	if(num>0){
         try {
              Thread.sleep(100);
          }catch (Exception e){
              e.printStackTrace();
          }
          System.out.println("tickets:"+num--);
    }
}

public void run(){
    while(ture){
        doit();
    }
}

这样执行的结果与代码块无异。

标签:java,synchronized,Thread,num,线程,new,多线程,tread
来源: https://blog.csdn.net/qq_44182694/article/details/122645183

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有