Java基础学习:多线程20(线程同步:Synchronized)

Java基础学习:多线程20

  • 线程同步:Synchronized(同步方法、同步代码块)

     

    • 同步方法:

      • 由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括2种方法:

        //synchronized 方法和 synchronized块:

        //同步方法:
        public synchronized void method(int ...){...};
      • synchronzed方法控制“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行;

        //缺陷:若将一个大的方法声明为synchronized将会影响效率

         

      • synchronzed的实现原理:队列+锁;

         

    • 同步方法的弊端:

      • 方法里面需要修改的内容才需要锁;

      • 锁的太多,浪费资源;

         

         

    • 同步块:

      • 同步块语法:

        synchronized (Obj) { }
        //Obj称之为同步监视器;
        //Obj可以是任意对象,但是推荐使用共享资源作为监视器;
      • 同步方法种无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,后者是class[反射种讲解];

         

    • 同步监视器的执行过程:

      • 第一个线程访问,锁定同步监视器,执行其中代码;

      • 第二个线程访问,发现同步监视器被锁定,无法访问;

      • 第一个线程访问完毕,解锁同步监视器;

      • 第二个线程访问,发现同步监视器没有锁,然后锁定并访问;

 

  • 修改之前的三个不安全案例

    package com.ljx3.syn;

    /**
    * 不安全的买票:
    * 1,线程不安全,有负数;
    * 2,
    *
    */
    public class UnSafeBuyTicket {

       public static void main(String[] args) {

           //声明一个买票对象
           BuyTicket b=new BuyTicket();


           //三个人买票
           new Thread(b,"小明").start();
           new Thread(b,"老师").start();
           new Thread(b,"黄牛党").start();

      }

    }

    //买票
    class BuyTicket implements Runnable{

       //票
       private int ticketNums=10;

       boolean flag=true;//外部停止方式


       @Override
       public void run() {
           //买票
           while (flag){
               buy();
          }

      }

       //synchronized 同步方法,锁的是this
       private synchronized void buy(){
           //判断是否有票
           if(ticketNums<=0){
               flag=false;
               return;
          }
           try {
               Thread.sleep(100);//放大问题的发生性
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
           //买票
           System.out.println(Thread.currentThread().getName()+"买到票了"+ticketNums-- );

      }
    }

     

  • 代码案例:list加锁

    package com.ljx3.syn;

    import java.util.ArrayList;
    import java.util.List;

    /**
    * 线程不安全的集合:
    *
    */
    public class UnSafeList {
       public static void main(String[] args) {

           List<String> list=new ArrayList<String>();

           for (int i = 0; i < 10000; i++) {
               new Thread(()->{
                   synchronized (list){
                       list.add(Thread.currentThread().getName());
                  }

              }).start();
          }
           try {
               Thread.sleep(3000);
          } catch (InterruptedException e) {
               e.printStackTrace();
          }
           System.out.println(list.size());//9997

      }
    }

     

  • 笔记:

    • synchronized:默认锁定是this,是它本身;

 

 

 

 

posted @   gzs1024  阅读(131)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示