synchronized用在方法上锁住的是什么?

锁住的是当前对象的当前方法,会使得其他线程访问该对象的synchronized方法或者代码块阻塞,但并不会阻塞非synchronized方法。

脏读

一个常见的概念。在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实是被更改过的。注意这里 局部变量是不存在脏读的情况

public class ThreadDomain13
{
private int num = 0; public void addNum(String userName)
{
try
{
if ("a".equals(userName))
{
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
}
else
{
num = 200;
System.out.println("b set over!");
}
System.out.println(userName + " num = " + num);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}

写两个线程分别去add字符串"a"和字符串"b":

public class MyThread13_0 extends Thread
{
private ThreadDomain13 td; public MyThread13_0(ThreadDomain13 td)
{
this.td = td;
} public void run()
{
td.addNum("a");
}
}
public class MyThread13_1 extends Thread
{
private ThreadDomain13 td; public MyThread13_1(ThreadDomain13 td)
{
this.td = td;
} public void run()
{
td.addNum("b");
}
}

写一个主函数分别运行这两个线程:

public static void main(String[] args)
{
ThreadDomain13 td = new ThreadDomain13();
MyThread13_0 mt0 = new MyThread13_0(td);
MyThread13_1 mt1 = new MyThread13_1(td);
mt0.start();
mt1.start();
}
//看一下运行结果
a set over!
b set over!
b num = 200
a num = 200

按照正常来看应该打印"a num = 100"和"b num = 200"才对,现在却打印了"b num = 200"和"a num = 200",这就是线程安全问题。我们可以想一下是怎么会有线程安全的问题的:

1、mt0先运行,给num赋值100,然后打印出"a set over!",开始睡觉

2、mt0在睡觉的时候,mt1运行了,给num赋值200,然后打印出"b set over!",然后打印"b num = 200"

3、mt1睡完觉了,由于mt0的num和mt1的num是同一个num,所以mt1把num改为了200了,mt0也没办法,对于它来说,num只能是100,mt0继续运行代码,打印出"a num = 200"

分析了产生问题的原因,解决就很简单了,给addNum(String userName)方法加同步即可:

多线程线synchronized关键字加到方法上

public class ThreadDomain13
{
private int num = 0; public synchronized void addNum(String userName)
{
try
{
if ("a".equals(userName))
{
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
}
else
{
num = 200;
System.out.println("b set over!");
}
System.out.println(userName + " num = " + num);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
} 复制代码 看一下运行结果: a set over!
a num = 100
b set over!
b num = 200

多个对象多个锁

在同步的情况下,把main函数内的代码改一下:

public static void main(String[] args)
{
ThreadDomain13 td0 = new ThreadDomain13();
ThreadDomain13 td1 = new ThreadDomain13();
MyThread13_0 mt0 = new MyThread13_0(td0);
MyThread13_1 mt1 = new MyThread13_1(td1);
mt0.start();
mt1.start();
} 看一下运行结果: a set over!
b set over!
b num = 200
a num = 100

这里有一个重要的概念。关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,这里如果是把一段代码或方法(函数)当作锁,其实获取的也是对象锁,只是监视器(对象)不同而已,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁,其他线程都只能呈等待状态。但是这有个前提:既然锁叫做对象锁,那么势必和对象相关,所以多个线程访问的必须是同一个对象

如果多个线程访问的是多个对象,那么Java虚拟机就会创建多个锁,就像上面的例子一样,创建了两个ThreadDomain13对象,就产生了2个锁。既然两个线程持有的是不同的锁,自然不会受到"等待释放锁"这一行为的制约,可以分别运行addNum(String userName)中的代码。

synchronized(this)锁住的是什么?

锁住的是当前的对象。当synchronized块里的内容执行完之后,释放当前对象的锁。同一时刻若有多个线程访问这个对象,则会被阻塞。
synchronized(object)锁住的什么?

锁住的是object对象。当synchronized块里的内容执行完之后,释放object对象的锁。同一时刻若有多个线程访问这个对象,则会被阻塞。

这里需要注意的是如果object为Integer、String等等包装类时(new出的对象除外),并不会锁住当前对象,也不会阻塞线程。因为包装类是final的,不可修改的,如果修改则会生成一个新的对象。所以,在一个线程对其进行修改后,其他线程在获取该对象的锁时,该对象已经不是原来的那个对象,所以获取到的是另一个对象的锁,所以不会产生阻塞。

Java中Synchronized的用法:https://blog.csdn.net/luoweifu/article/details/46613015

Java并发,synchronized锁住的内容的更多相关文章

  1. java 并发多线程 锁的分类概念介绍 多线程下篇(二)

    接下来对锁的概念再次进行深入的介绍 之前反复的提到锁,通常的理解就是,锁---互斥---同步---阻塞 其实这是常用的独占锁(排它锁)的概念,也是一种简单粗暴的解决方案 抗战电影中,经常出现为了阻止日 ...

  2. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

  3. java 并发——synchronized

    java 并发--synchronized 介绍 在平常我们开发的过程中可能会遇到线程安全性的问题,为了保证线程之间操作数据的正确性,我们第一想到的可能就是使用 synchronized 并且 syn ...

  4. Java并发 - (无锁)篇6

    , 摘录自葛一鸣与郭超的 [Java高并发程序设计]. 本文主要介绍了死锁的概念与一些相关的基础类, 摘录自葛一鸣与郭超的 [Java高并发程序设计]. 无锁是一种乐观的策略, 它假设对资源的访问是没 ...

  5. 从源码学习Java并发的锁是怎么维护内部线程队列的

    从源码学习Java并发的锁是怎么维护内部线程队列的 在上一篇文章中,凯哥对同步组件基础框架- AbstractQueuedSynchronizer(AQS)做了大概的介绍.我们知道AQS能够通过内置的 ...

  6. Java并发编程锁之独占公平锁与非公平锁比较

    Java并发编程锁之独占公平锁与非公平锁比较 公平锁和非公平锁理解: 在上一篇文章中,我们知道了非公平锁.其实Java中还存在着公平锁呢.公平二字怎么理解呢?和我们现实理解是一样的.大家去排队本着先来 ...

  7. Java并发编程锁系列之ReentrantLock对象总结

    Java并发编程锁系列之ReentrantLock对象总结 在Java并发编程中,根据不同维度来区分锁的话,锁可以分为十五种.ReentranckLock就是其中的多个分类. 本文主要内容:重入锁理解 ...

  8. 精通java并发-synchronized关键字和锁

    目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages synchronized关键字和锁 示例代码 public class MyThreadTest2 { public ...

  9. Java线程同步:synchronized锁住的是代码还是对象

    所以我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步.这叫减小锁的粒度,使代码更大程度的并发.原因是基于以上的思想,锁的代码段太长 ...

随机推荐

  1. 【WPF学习】第四十九章 基本动画

    在前一章已经学习过WPF动画的第一条规则——每个动画依赖于一个依赖项属性.然而,还有另一个限制.为了实现属性的动态化(换句话说,使用基于时间的方式改变属性的值),需要有支持相应数据类型的动画类.例如, ...

  2. 解决在jsp页面中使用jstl无法遍历request域中list集合的问题

    解决在jsp页面中使用jstl无法遍历request域中list集合的问题 1. 前言 ​ 最近在写一个很简单的Javaweb项目,里面需要将request域中的list集合加载到jsp页面,我使用e ...

  3. 洛谷P3719 [AHOI2017初中组]rexp

    洛谷P3719 [AHOI2017初中组]rexp 题目背景 以下为不影响题意的简化版题目. 题目描述 给出一个由(,),|,a组成的序列,求化简后有多少个a. 化简规则: 1.形如aa...a|aa ...

  4. Linux 文件(持续更新)

    一.文件类型 Linux操作系统把所有内容(文件.图片.视频.设备)都当作文件看待.处理,即一切皆文件. Linux系统把所有文件分为七种类型: 文件类型 文件类型标识 说明 使用ls -l命令查看文 ...

  5. 安装JumpServer到CentOS(YUM)

    运行环境 系统版本:CentOS Linux release 7.6.1810 (Core) 软件版本:JumpServer-1.4.8 硬件要求:最低2核4GB 官方文档:https://docs. ...

  6. C语言 杂货整理

    C语言 杂货整理 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include ...

  7. linux中安装nginx时查看修改80端口时没有iptables文件的内容?? 求解

  8. oracle DB 使用注意点小结

    1.DDL 后不需要添加commit;语句,因为Oracle数据库的DDL不支持transaction,执行即commit: DDL(Data Definition Language): 数据定义语言 ...

  9. NODEJS 中使用二维码 qr-image

    https://www.npmjs.com/package/qr-image npm install qr-image var qr = require('qr-image'); var code = ...

  10. 小白的java学习之路 “ 选择结构(二)”

    switch 选择结构: 为什么使用switch选择结构: switch选择结构可以更好地解决等值判断问题. switch选择结构的四个关键字: switch    case    default   ...