一,介绍

本文介绍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读取用户名和密码。因此,就避免了数据的不一致性而导致的脏读问题。

最新文章

  1. ubuntu vps 安装java
  2. BZOJ-1206 虚拟内存 Hash+离散化+Priority_Queue
  3. mysql链接数据库时报错
  4. Spring MVC Controller中解析GET方式的中文参数会乱码的问题(tomcat如何解码)
  5. Java druid
  6. C#预编译指令
  7. 第三百四十二天 how can I 坚持
  8. STM32学习笔记——新建工程模板步骤(向原子哥学习)
  9. what does Html.HiddenFor () for ?
  10. php 前台数据显示
  11. 面向面试题和实际使用谈promise
  12. JavaScript的作用;JS常见的三种对话框;==和===的区别;函数内部参数数组arguments在函数内部打印实参;JS的误区:没有块级作用域
  13. POJ 2135 最小费用最大流
  14. C++ Primer 有感(标准库set类型)
  15. [官网]Windows modules
  16. 第七章 LED将为我闪烁:控制发光二级管
  17. C# wkhtmltopdf 将html转pdf(详解)
  18. Linux下的换行符\n\r以及txt和word文档的使用
  19. Jmeter(三十九)获取响应结果中参数出现的次数(转载)
  20. ApplicationContextAware的使用

热门文章

  1. [Bzoj3675][Apio2014]序列分割(斜率优化)
  2. easyui分页时,总页数出错
  3. Go视频教程整理转
  4. 使用Swagger生成Spring Boot REST客户端(支持Feign)(待实践)
  5. 【spring boot】mybatis启动报错:Consider defining a bean of type 'com.newhope.interview.dao.UserMapper' in your configuration. 【Mapper类不能被找到】@Mapper 和@MapperScan注解的区别
  6. python远程访问hive
  7. poj 1659 Frogs' Neighborhood 度序列可图化 贪心
  8. mysql 复制数据库
  9. 【试水CAS-4.0.3】第06节_CAS服务端配置HTTPS
  10. jquery 获取下拉框 某个text='xxx'的option的属性 非选中 如何获得select被选中option的value和text和......