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. Deepin下将Caps映射为Control_L键

    xmodmap -e 'clear Lock' -e 'keycode 0x42 = Control_L'

  2. toj 3761 Egg Problem (好题~~)

    Egg Problem 时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte总提交: 22 测试通过: 7 描述 There is a very interest ...

  3. python学习------文件的读与写

    f=open("yesterday","r",encoding="utf-8") #文件句柄 data=f.read() data2=f.r ...

  4. Umi 小白纪实(三)—— 震惊!路由竟然如此强大!

    在<Umi 小白纪实(一)>中有提到过简单的路由配置和使用,但这只是冰山一角 借用一句广告词,Umi 路由的能量,超乎你的想象 一.基本用法 Umi 的路由根结点是全局 layout  s ...

  5. 如何把已有的本地git仓库,推送到远程新的仓库(github private)并进行远程开发;

    最近因为疫情,在家干活,连接不上之前的gitlab 服务器:所以不得把现有的代码迁移到github 的私有仓库来进行开发:下面简要记录迁移的过程: 首先,确保你已经配置好本地访问远程私有仓库的所有权限 ...

  6. CF #622 div.2

    序 ~ieowjf~~ 真的只有老邱在支持我吗(雾 #622 T1 此题做法显然,但是,不知为何,就是会评测机有小问题...无语 上 SingerCoder 的码,不知为何,我的码风总是毒瘤 #inc ...

  7. LeetCode刷题专题

    1. https://leetcode-cn.com/problems/container-with-most-water/ 思想:左右边界  i,j   向中间收敛 ,左右夹逼 方法一: 一维数组的 ...

  8. 数据结构(集合)学习之Map(二)

    集合 框架关系图 补充:HashTable父类是Dictionary,不是AbstractMap. 一:HashMap中的链循环: 一般来说HashMap中的链循环会发生在多线程操作时(虽然HashM ...

  9. 吴裕雄--天生自然 python数据分析:医疗费数据分析

    import numpy as np import pandas as pd import os import matplotlib.pyplot as pl import seaborn as sn ...

  10. 【笔记】机器学习 - 李宏毅 - 12 - CNN

    Convolutional Neural Network CNN 卷积神经网络 1. 为什么要用CNN? CNN一般都是用来做图像识别的,当然其他的神经网络也可以做,也就是输入一张图的像素数组(pix ...