你的位置:首页 > 软件开发 > Java > Thread线程基础 第二篇:多线程之间的同步

Thread线程基础 第二篇:多线程之间的同步

发布时间:2017-12-01 07:00:08
序; 大家好,这次我们就来学一下线程之间的同步操作: 一、 如果我们要使用多线程操作同一个对象或者数据时,那么就要先知道为何要使用同步?   java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如对同一个数据的增删改 ...

Thread线程基础   第二篇:多线程之间的同步

序;  大家好,这次我们就来学一下线程之间的同步操作:

    一、 如果我们要使用多线程操作同一个对象或者数据时,那么就要先知道为何要使用同步? 

 

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

 

   由此,我们可以得出同步的概念:

 

    所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。例如Window API函数SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给调用者。

 

    在多线程编程里面,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何时刻,最多有一个线程访问,以保证数据的完整性

 

   二、   如何使用同步?

 

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

 

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

 

      实现线程安全:synchronized

 

    (1)方法加锁

      public synchronized void a(){

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

      }

 

    (2)代码块加锁

      public void b(){

        synchronized(共享对象){

        i++;

        }

      }

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

   

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

 

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

 

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

 

      1)实现Runnable接口的卖票的类  

/***@functon 卖票系统中的窗口 *@author 温煦(昵称:沉沦之巅)*@time 2017.12.1 */package TicketShop;//此类为实现Runnable的接口的方法来演示线程public class SaleTicketsbyRannable implements Runnable{ //获得票的类 public Tickets tic; //有参构造 public SaleTicketsbyRannable(Tickets tic) {  super();  this.tic = tic; } //实现Runnable接口中的run方法,进行重写 @Override public void run() {  //while判断当票数为零时停止销售  while(tic.getCount()>=0){   sale();  } }  //卖票的方法(注意注意:这里的synchronized 关键字起这关键的作用,因为有它才能完成线程的同步,可以说是一大功臣了,哈哈) public synchronized void sale() {  //获取当前线程的名字,直观的看出是哪个线程  String threadname = Thread.currentThread().getName();  //判断当票数大于0时卖票  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是输出“票已售空"   //因为while还在循环,所以要减一,否则会进入“票已售空”无限死循环   tic.setCount(tic.getCount()-1);   System.out.println(threadname+"的票已售空!");  } } //票类的set和get方法 public Tickets getTic() {  return tic; } public void setTic(Tickets tic) {  this.tic = tic; }}

 

 

    

      2)票的类

 

/** *@functon 卖票系统中的总票数 *@author 温煦(昵称:沉沦之巅) *@time 2017.12.1 */package TicketShop;//此类为要卖的票,所有要卖的票都要从这里取public class Tickets { //因是一个demo,所以票类里没有那么多的属性值 //票的总数 private int count; //有参构造 public Tickets(int count) {  super();  this.count = count; }  //无参构造 public Tickets() {  super(); }  //set和get方法 public int getCount() {  return count; } public void setCount(int count) {  this.count = count; }}

     

     3)演示四个窗口卖票结果的测试类(注意注意:与上一篇不一样的地方就是这,也是最重要的部分)

 

/** *@functon 卖票系统演示(用实现Rannble接口的方法) *@author 温煦(昵称:沉沦之巅) *@time 2017.12.1 */package TicketShop;public class TestSale { public static void main(String[] args) {    //new一个票的实体类,并给它50张票  Tickets tic = new Tickets(50);  //创建   SaleTicketsbyRannable str = new SaleTicketsbyRannable(tic);  //因此对象没有继承Thread类所以不可以直接调用  //需要new一个Thread,现在要new 4 个了,因为有四个窗口了哦  Thread st1 = new Thread(str,"窗口1");//给每个new线程后,加个名字,来区分四个窗口  Thread st2 = new Thread(str,"窗口2");  Thread st3 = new Thread(str,"窗口3");  Thread st4 = new Thread(str,"窗口4");  //执行  st1.start();  st2.start();  st3.start();  st4.start(); }}

 

  

      4)演示效果(因数据太多,中间就省略了哦)

 

  窗口1:第50张票已售出!
  窗口4:第49张票已售出!
  窗口4:第48张票已售出!
  窗口3:第47张票已售出!

...
...

窗口4:第11张票已售出!窗口1:第10张票已售出!窗口4:第9张票已售出!窗口4:第8张票已售出!窗口3:第7张票已售出!窗口3:第6张票已售出!窗口2:第5张票已售出!窗口3:第4张票已售出!窗口3:第3张票已售出!窗口3:第2张票已售出!窗口4:第1张票已售出!窗口4的票已售空!窗口1的票已售空!窗口3的票已售空!窗口2的票已售空!

 

     在演示效果中,大家可以看到,四个卖票的窗口,同时卖的是同一种票,而且卖完之后不会在另外几个窗口内出现,虽然是同时开始售票,但是在内部机制里还是一个一个的 来执行的,里面的执行是没有顺序的,也就是说,哪个线程先获得资源,哪个线程就先执行,到售完票以后,若再次访问窗口,则会提示“票已售完”的信息!这就是线程之间的同步!

    好了,这就是本篇的线程同步,又到了跟大家sayGoodbay的时候了,在这里祝大家在学习Java的道路上越走越远!

    (本篇学完后,就表明你已经迈上了线程的第二节台阶,什么,你要问我一共有多少节台阶,嘻嘻,诚实的说,我也看不到头啊,哈哈,每一门知识都是博大精深的,诚然希望你学的越多越好!)

    (悄悄告诉你哦,第三篇是实现线程之间的通信,如果有兴趣就去看看吧!Thread线程基础   第二篇:多线程之间的同步Thread线程基础   第二篇:多线程之间的同步

 

 

海外公司注册、海外银行开户、跨境平台代入驻、VAT、EPR等知识和在线办理:https://www.xlkjsw.com

原标题:Thread线程基础 第二篇:多线程之间的同步

关键词:线程

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。