zoukankan      html  css  js  c++  java
  • JAVA Synchronized (二)

    一,介绍

    本文介绍JAVA多线程中的synchronized关键字作为对象锁的一些知识点。

    所谓对象锁,就是就是synchronized 给某个对象 加锁。关于 对象锁 可参考:这篇文章

    二,分析

    synchronized可以修饰实例方法,如下形式:

    1 public class MyObject {
    2 
    3     synchronized public void methodA() {
    4         //do something....
    5     }

    这里,synchronized 关键字锁住的是当前对象。这也是称为对象锁的原因。

    为啥锁住当前对象?因为 methodA()是个实例方法,要想执行methodA(),需要以 对象.方法() 的形式进行调用(obj.methodA(),obj是MyObject类的一个对象,synchronized就是把obj这个对象加锁了)。

    上面代码也可写成这样:

    复制代码
    1 public class MyObject {
    2 
    3     public void methodA() {
    4         synchronized(this){
    5             //do something....
    6         }
    7     }
    复制代码

    三,特点

    使用synchronized关键字同步一个明显的特点是:MyObject类中定义有多个synchronized修饰的实例方法时,若多个线程拥有同一个MyObject类的对象则这些方法只能以同步的方式执行。即,执行完一个synchronized修饰的方法后,才能执行另一个synchronized修饰的方法。

    如下:

    复制代码
     1 public class MyObject {
     2 
     3     synchronized public void methodA() {
     4         //do something....
     5     }
     6 
     7     synchronized public void methodB() {
     8         //do some other thing
     9     }
    10 }
    复制代码

    MyObject类中有两个synchronized修饰的方法。

    复制代码
     1 public class ThreadA extends Thread {
     2 
     3     private MyObject object;
     4 //省略构造方法
     5     @Override
     6     public void run() {
     7         super.run();
     8         object.methodA();
     9     }
    10 }
    复制代码

    线程A执行methodA()

    复制代码
    public class ThreadB extends Thread {
    
        private MyObject object;
    //省略构造方法
        @Override
        public void run() {
            super.run();
            object.methodB();
        }
    }
    复制代码

    线程B执行methodB()

    复制代码
    public class Run {
        public static void main(String[] args) {
            MyObject object = new MyObject();
    
            //线程A与线程B 持有的是同一个对象:object
            ThreadA a = new ThreadA(object);
            ThreadB b = new ThreadB(object);
            a.start();
            b.start();
        }
    }
    复制代码

    由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是必须是同步的,比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。

    四,结论

    从上可以看出,本文中讲述的 synchronized 锁的范围是整个对象。如果一个类中有多个synchronized修饰的同步方法,且多个线程持有该类的同一个对象(该类的相同的对象),尽管它们调用不同的方法,各个方法的执行也是同步的。

    如果各个同步的方法之间没有共享变量,或者说各个方法之间没有联系,但也只能同步执行,这会影响效率。

    五,应用--使用synchronized避免 因数据不一致性而导致读脏数据的情况

    如下示例:

    复制代码
     1 public class MyObject {
     2 
     3     private String userName = "b";
     4     private String passWord = "bb";
     5     
     6     synchronized public void methodA(String userName, String passWord) {
     7         this.userName = userName;
     8         try{
     9             Thread.sleep(5000);
    10         }catch(InterruptedException e){
    11             
    12         }
    13         this.passWord = passWord;
    14     }
    15 
    16     synchronized public void methodB() {
    17         System.out.println("userName" + userName + ": " + "passWord" + passWord);
    18     }
    19 }
    复制代码

    methodA()负责更改用户名和密码。在现实中,一个用户名对应着一个密码。。。

    methodB()负责读取用户名和密码。

    如果methodB()没有用synchronized 修饰,线程A在调用methodA()执行到第7行,更改了用户名,因某种原因(比如在第9行睡眠了)放弃了CPU。

    此时,如果线程B去执行methodB(),那么读取到的用户名是线程A更改了的用户名("a"),但是密码却是原来的密码("bb")。因为,线程A睡眠了,还没有来得及更改密码。

    但是,如果methodB()用synchronized修饰,那么线程B只能等待线程A执行完毕之后(即改了用户名,也改了密码),才能执行methodB读取用户名和密码。因此,就避免了数据的不一致性而导致的脏读问题。

  • 相关阅读:
    You are not late! You are not early!
    在同一个服务器(同一个IP)为不同域名绑定的免费SSL证书
    Vue.js Is Good, but Is It Better Than Angular or React?
    It was not possible to find any compatible framework version
    VS增加插件 Supercharger破解教程
    Git使用ssh key
    Disconnected: No supported authentication methods available (server sent: publickey)
    VS 2013打开.edmx文件时报类型转换异常
    asp.net MVC4 框架揭秘 读书笔记系列3
    asp.net MVC4 框架揭秘 读书笔记系列2
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/7217561.html
Copyright © 2011-2022 走看看