zoukankan      html  css  js  c++  java
  • 线程安全-线程同步

    1.什么是线程安全:

        java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如对同一个数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性准确性

    二、   如何使用同步?

        在网上简单的搜了一下,发现同步的方式有5-7种,其实同步来同步去,里面的原理是没有变化的,那么今天就简单来讲一种:

        1、用 synchronized 关键字修饰方法、代码块

          实现线程安全:synchronized

        (1)方法加锁

          public synchronized void a(){

            //在该方法中可以访问共享的对象

          }

        (2)代码块加锁

          public void b(){

            synchronized(共享对象){

            i++;

            }

          }

          注:同步是一种高开销的操作,因此应该尽量减少同步的内容。 通常没有必要同步整个方法,使用synchronized代码块同步关键代码即可。 

       

    三、如上所说,我们就接着上一篇的卖票系统来增加多个窗口卖票,也就是增加多个线程,来演示一下线程的同步:

         (一)演示背景:假设我们有一个卖票系统,共有50张票,原来只有一个窗口,现在因为近期生意火爆,顾客排队等待时间较长,所以现在要增加三个窗口,那么写到代码中就是增加三个线程(一个窗口代表卖票的一个线程,那选在就一共有四个线程)

         (二)代码的类与方法与上一篇的一样,不一样的就是在测试阶段,增加了三个线程,代码如下:

          2)票的类     

    /**
    *@ClassName Tickets
    *@Description TODD
    *@AUTHOR sh-wangbs
    *@Date 2019/2/279:55
    *@Version 1.0
    **/
    //该注解省去了 get set 方法
    @Data
    public class Tickets {
    //票的总数
    private int count;

    //有参构造
    public Tickets(int count) {
    super();
    this.count = count;
    }
    //无参构造
    public Tickets() {
    super();
    }
    }
      2)实现Runnable接口的卖票的类 
      
    **
    *@ClassName SaleTicketsbyRannable
    *@Description TODD
    *@AUTHOR sh-wangbs
    *@Date 2019/2/279:55
    *@Version 1.0
    **/
    @Data
    public class SaleTicketsbyRannable implements Runnable {
    //获得票的类
    public Tickets tic;

    //有参构造
    public SaleTicketsbyRannable(Tickets tic) {
    super();
    this.tic = tic;
    }

    @Override
    public void run() {
    while (tic.getCount()>0){
    sale();
    }
    }

    //卖票的方法(这里的synchronized 关键字起这关键的作用,就是给该方法加锁)
    public synchronized void sale() {
    //获取当前线程的名字,直观的看出是哪个线程
    String threadname = Thread.currentThread().getName();
    //如果票数大于零卖票
    if(tic.getCount()>0){
    System.out.println(threadname+":第"+tic.getCount()+"张票已售出!");
    //卖票后总票数减1
    tic.setCount(tic.getCount()-1);
    try {
    //线程沉睡0.2秒,只是方便看演示效果
    Thread.currentThread().sleep(200);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }else{
    //当票数为0是输出“票已售空"
    tic.setCount(tic.getCount());
    System.out.println(threadname+"的票已售空!");
    }
    }
    }
      3)演示五个窗口卖票结果的测试类
    /***
    * @Description: 卖票测试类
    * @Param:
    * @return:
    * @author: wangbs
    * @create: 2019/2/27 11:06
    */

    public class TestSaleTickets {
    public static void main(String[] args) {
    //票的实体类,有100张票
    Tickets tic = new Tickets(100);
    //创建一个多线程
    SaleTicketsbyRannable str = new SaleTicketsbyRannable(tic);
    //开启五个线程也就是五个卖票窗口
    Thread thread1 = new Thread(str,"卖票窗口1");
    Thread thread2 = new Thread(str,"卖票窗口2");
    Thread thread3 = new Thread(str,"卖票窗口3");
    Thread thread4 = new Thread(str,"卖票窗口4");
    Thread thread5 = new Thread(str,"卖票窗口5");
    //执行
    thread1.start();
    thread2.start();
    thread3.start();
    thread4.start();
    }
    }
     4)演示效果

    由结果可知,五个卖票的窗口,同时开始售票,但是在内部机制里还是一个一个的 来执行的,里面的执行是无序的,买次售票都需要对应的线程抢占资源,才能卖票,也就是说,哪个线程先获得资源,哪个线程就先执行,到售完票以后,若再次访问窗口,则会提示“票已售完”的信息!这就是线程之间的同步!

        (下一篇我会讲下线程间的通信问题)

    
    
  • 相关阅读:
    Alpha冲刺(4/6)
    Alpha冲刺(3/6)
    Alpha冲刺(2/6)
    Alpha冲刺(1/6)
    团队Git现场编程实战
    团队项目-需求分析报告
    团队项目-选题报告
    第二次结对编程作业
    第一次团队展示
    第一次结对编程作业
  • 原文地址:https://www.cnblogs.com/xiaowangbangzhu/p/10442423.html
Copyright © 2011-2022 走看看