zoukankan      html  css  js  c++  java
  • Java并发编程:synchronized

    • 什么时候会出现线程安全问题

        当多个线程同时访问同一个资源时就有可能出现问题。最终的执行结果和实际上的愿望相违背,或者直接导致程序出错

    • 如何解决线程安全问题

        基本上所有的并发模式在解决线程安全问题时,都采用了“序列号访问临界资源”的方案。即在同一时刻,只能有一个线程能够访问临界资源,也称作同步互斥访问。

        通常来说,在访问临界资源的代码前面加一个锁,当访问结束后释放锁,让其他线程继续访问。

        在java中实现了两张方法来实现同步互斥访问  synchronized和lock

    • synchronized的使用

        互斥锁:能够达到互斥访问的锁。

        如果对临界资源加上互斥锁,当一个线程访问临界资源时,其他线程只能等待。

        在java中每一个对象都一个锁标记(monitor),也被称为监视器。多线程访问时某个对象时,只有线程获取到了该对象的锁,才能继续访问。

        在java中可以直接使用synchronized关键字来标记一段代码或者一个方法。当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。

        对于synchronized方法或者synchronized代码块,当代码出现异常时,jvm会自动释放当前线程占用的锁,因此不会因为异常导致死锁。

    1. 锁方法
      public class TestThread {
          public static void main(String[] args)  {
              final InsertData insertData = new InsertData();
      
              new Thread() {
                  public void run() {
                      insertData.insert(Thread.currentThread());
                  };
              }.start();
      
      
              new Thread() {
                  public void run() {
                      insertData.insert(Thread.currentThread());
                  };
              }.start();
          }
      }
      class InsertData {
          private ArrayList<Integer> arrayList = new ArrayList<Integer>();
      
          public synchronized void insert(Thread thread){
              for(int i=0;i<5;i++){
                  try {
                      sleep(100);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  System.out.println(thread.getName()+"在插入数据"+i);
                  arrayList.add(i);
              }
      
          }
      }

      锁住的对象是 insertData ,当创建多个insertData对象分别执行insert方式时,锁就不生效了

    2. 锁代码块
      public class TestThread {
          public static void main(String[] args)  {
              final InsertData insertData = new InsertData();
      
              new Thread() {
                  public void run() {
                      insertData.insert(Thread.currentThread());
                  };
              }.start();
      
      
              new Thread() {
                  public void run() {
                      insertData.insert(Thread.currentThread());
                  };
              }.start();
          }
      }
      class InsertData {
          private ArrayList<Integer> arrayList = new ArrayList<Integer>();
      
          public  void insert(Thread thread){
              synchronized(this){
                  for(int i=0;i<5;i++){
                      try {
                          sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      System.out.println(thread.getName()+"在插入数据"+i);
                      arrayList.add(i);
                  }
              }
          }
      }

      和方法锁一样

    3. 锁静态方法
      public class TestThread {
          public static void main(String[] args)  {
              final InsertData insertData = new InsertData();
              final InsertData insertData2 = new InsertData();
      
              new Thread() {
                  public void run() {
                      insertData.insert(Thread.currentThread());
                  };
              }.start();
      
      
              new Thread() {
                  public void run() {
                      insertData2.insert(Thread.currentThread());
                  };
              }.start();
          }
      }
      class InsertData {
          private static ArrayList<Integer> arrayList = new ArrayList<Integer>();
      
          public static synchronized void insert(Thread thread){
              for(int i=0;i<5;i++){
                  try {
                      sleep(100);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  System.out.println(thread.getName()+"在插入数据"+i);
                  arrayList.add(i);
              }
      
          }
      }

      锁住的类,同一个类的对象都被锁住

      参考:http://www.cnblogs.com/dolphin0520/p/3923737.html

  • 相关阅读:
    spring aop的@Before,@Around,@After,@AfterReturn,@AfterThrowing的理解
    详解Spring 框架中切入点 pointcut 表达式的常用写法
    Spring计时器StopWatch使用
    Java反射-解析ProceedingJoinPoint的方法参数及参数值
    MySQL 中 datetime 和 timestamp 的区别与选择
    java在注解中绑定方法参数的解决方案
    spring aop的@Before,@Around,@After,@AfterReturn,@AfterThrowing的理解
    LocalDateTime和Date的比较与区别
    idea启动java服务报错OutOfMemoryError: GC overhead limit exceeded解决方法
    java在注解中绑定方法参数的解决方案
  • 原文地址:https://www.cnblogs.com/zhangyaxiao/p/6594453.html
Copyright © 2011-2022 走看看