zoukankan      html  css  js  c++  java
  • 并发编程之synchronize

    synchronized是Java中的关键字,是一种常用的线程同步锁。

    用法

    注意:在理解synchronized时,要知道一个核心点,synchronized锁定的不是代码,而是对象。使用synchronized时,其会申请对象的堆内存,进行锁定。

    写法一

        Object o = new Object(); // 锁对象
        public void test01(){
          	//任何线程要执行以下的代码,必须先拿到锁
            synchronized (o){  
                // doSomething...
            }
        }
    

    写法二

    上述写法是创建一个锁对象,其实可以自身作为锁对象。

        public void test02(){
            synchronized (this){ 
              	// doSomething...
            }
        }
    

    写法三

    同写法二。

        public synchronized void test03(){
            // doSomething...
        }
    

    写法四

    锁定静态方法。静态方法是属于类方法,没有对象。

        public synchronized static void test04(){
        }
    

    写法五

    同写法四

        public static void test04(){
            synchronized (SynchronizeTest.class){
            }
        }
    

    测试线程安全问题

    演示代码:

    public class TestSynch implements Runnable{
        private int count = 10;
        @Override
        public /*synchronized*/ void run() {
            count--;
            System.out.println(Thread.currentThread().getName()+"count="+count);
        }
        public static void main(String[] args) {
            TestSynch t = new TestSynch();
            for (int i = 0; i < 8; i++) {
                new Thread(t,"结果是"+i).start();
            }
        }
    }
    

    结果是:

    加入synchronized:

    注意事项

    1. 加锁方法和不加锁方法

      public class Account {
          int count = 100;
        
        	// 写入数据
          public synchronized void set(int s){
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              this.count = s;
          }
        
        	// 读取数据
          public /*synchronized*/ void get(){
              System.out.println(count);
          }
          public static void main(String[] args) {
              Account a = new Account();
              new Thread(()->a.set(1)).start();
              a.get();
              try {
                  Thread.sleep(500);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              a.get();
          }
      }
      

      在实际业务场景中,往往将读方法不加锁,写的方法加锁,这样会导致一个问题,也就是读的数据是写之前的数据,导致脏读问题。

    解决方案就是,在读方法上也加锁。

    1. 加锁方法不影响不加锁方法的执行;

    2. 加锁方法访问另外一个加锁方法,一个线程拥有某个对象的锁,再次申请的时候可以再次得到这把锁(相当于锁上了两把同样的锁);子类的同步方法调用父类的同步方法也可以;

    3. synchronized 遇到异常,锁会被释放。如果不想该锁被释放,就直接catch;

    4. 不要以字符创常量作为锁对象。

      public class StringAsSynchObject {
          private String stra = "hello";
          private String strb = "hello";
          void test1(){
              synchronized (stra){
              }
          }
          void test2(){
              synchronized (strb){
              }
          }
      }
      

      在上述代码中,因为stra和strb 锁的是同一个对象,如果用到了同一个类库,在该类库中的代码锁定了字符串"hello",我们读不到源码,而在业务代码中也锁定了同样的字符串,这就有可能会造成非常诡异的死锁阻塞。因为程序和类库不经意用了同一把锁。(这种情况一般没办法调试)。所以通常不要字符串作为锁定对象。

    5. synchronize 锁定的粒度越小(即锁定的业务代码越少),效率越高。

    6. synchronize 锁释放的情况:

      1)线程执行完毕;

      2)线程发生异常;

      3)线程进入休眠状态。

    7. synchronize 是互斥锁,可重入锁。

    8. wait()和notify()/notifyAll() 与 synchronize同时出现。


    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/10694661.html 版权声明:本文为博主原创文章,转载请附上博文链接!
  • 相关阅读:
    (一)Python入门-4控制语句:07嵌套循环-练习
    (一)Python入门-4控制语句:06for循环结构-遍历各种可迭代对象-range对象
    (一)Python入门-4控制语句:05while循环结构-死循环处理
    (一)Python入门-4控制语句:04多分支选择结构-选择结构的嵌套
    Java学习第三章 之 基础语法
    Java学习第二章 之 变量、数据类型和运算符
    Java学习第一章 之 初识Java
    JavaScrip学习笔记_JS中的foreach
    链接自动跟随光标
    LeetCode刷题记录_38. 报数
  • 原文地址:https://www.cnblogs.com/yanfei1819/p/10694661.html
Copyright © 2011-2022 走看看