并发编程之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:

注意事项
加锁方法和不加锁方法
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();
}
}
在实际业务场景中,往往将读方法不加锁,写的方法加锁,这样会导致一个问题,也就是读的数据是写之前的数据,导致脏读问题。

解决方案就是,在读方法上也加锁。
加锁方法不影响不加锁方法的执行;
加锁方法访问另外一个加锁方法,一个线程拥有某个对象的锁,再次申请的时候可以再次得到这把锁(相当于锁上了两把同样的锁);子类的同步方法调用父类的同步方法也可以;
synchronized 遇到异常,锁会被释放。如果不想该锁被释放,就直接catch;
不要以字符创常量作为锁对象。
public class StringAsSynchObject {
private String stra = "hello";
private String strb = "hello";
void test1(){
synchronized (stra){
}
}
void test2(){
synchronized (strb){
}
}
}
在上述代码中,因为stra和strb 锁的是同一个对象,如果用到了同一个类库,在该类库中的代码锁定了字符串"hello",我们读不到源码,而在业务代码中也锁定了同样的字符串,这就有可能会造成非常诡异的死锁阻塞。因为程序和类库不经意用了同一把锁。(这种情况一般没办法调试)。所以通常不要字符串作为锁定对象。
synchronize 锁定的粒度越小(即锁定的业务代码越少),效率越高。
synchronize 锁释放的情况:
1)线程执行完毕;
2)线程发生异常;
3)线程进入休眠状态。
synchronize 是互斥锁,可重入锁。
wait()和notify()/notifyAll() 与 synchronize同时出现。
作者:追梦1819
原文:https://www.cnblogs.com/yanfei1819/p/10694661.html
版权声明:本文为博主原创文章,转载请附上博文链接!
并发编程之synchronize的更多相关文章
- [转载]并发编程之Operation Queue和GCD
并发编程之Operation Queue http://www.cocoachina.com/applenews/devnews/2013/1210/7506.html 随着移动设备的更新换代,移动设 ...
- Java并发编程之CAS
CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替 ...
- 并发编程之wait()、notify()
前面的并发编程之volatile中我们用程序模拟了一个场景:在main方法中开启两个线程,其中一个线程t1往list里循环添加元素,另一个线程t2监听list中的size,当size等于5时,t2线程 ...
- 并发编程之 Exchanger 源码分析
前言 JUC 包中除了 CountDownLatch, CyclicBarrier, Semaphore, 还有一个重要的工具,只不过相对而言使用的不多,什么呢? Exchange -- 交换器.用于 ...
- 并发编程之 Condition 源码分析
前言 Condition 是 Lock 的伴侣,至于如何使用,我们之前也写了一些文章来说,例如 使用 ReentrantLock 和 Condition 实现一个阻塞队列,并发编程之 Java 三把锁 ...
- python并发编程之Queue线程、进程、协程通信(五)
单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...
- python并发编程之gevent协程(四)
协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块.由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成. 系列文章 python并发编程 ...
- python并发编程之asyncio协程(三)
协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...
- python并发编程之multiprocessing进程(二)
python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. 系列文章 python并发编程之threading线程(一) python并 ...
随机推荐
- linux 权限机制
系统每个文件都拥有特定的权限,所属用户及所属组,通过这样的机制限制哪些用户.哪些组可以对特定文件进行什么样的操作,一般分为读.写.执行三种权限. 每个进程都是以某个用户的身份运行,所以进程的权限与该用 ...
- Android-Activity横竖屏切换不杀死Activity 并监听横竖屏切换
在上一篇博客,Android-Activity临时数据的保存,中讲解到,当发生横竖屏切换的时候,系统会杀死Activity并重新启动Activity 系统会杀死Activity 12-12 08:11 ...
- [LeetCode 题解]: Triangle
前言 [LeetCode 题解]系列传送门: http://www.cnblogs.com/double-win/category/573499.html 1.题目描述 Given a tr ...
- “全栈2019”Java第二十二章:控制流程语句中的决策语句if-else
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- CF1106F Lunar New Year and a Recursive Sequence(矩阵快速幂+bsgs+exgcd)
题面 传送门 前置芝士 \(BSGS\) 什么?你不会\(BSGS\)?百度啊 原根 对于素数\(p\)和自然数\(a\),如果满足\(a^x\equiv 1\pmod{p}\)的最小的\(x\)为\ ...
- 洛谷P2462 [SDOI2007]游戏(哈希+最长路)
题面 传送门 题解 我们把字符的出现次数哈希起来,然后把每个点向能在它之后的点连边.那么这显然是一个\(DAG\),直接求最长路就行了 //minamoto #include<bits/stdc ...
- Spark JavaRDD、JavaPairRDD、Dataset相互转换与打印
主要内容: 1. List转JavaRDD,打印JavaRDD 2. List转JavaRDD,JavaRDD转JavaPairRDD,打印JavaPairRDD 3. JavaRDD<Stri ...
- Mysql创建、删除用户[转]
MySql中添加用户,新建数据库,用户授权,删除用户,修改密码(注意每行后边都跟个;表示一个命令语句结束): 1.新建用户 登录MYSQL: @>mysql -u root -p @>密码 ...
- debian下安装 locale 并设置 zh_CN.UTF-8 [转]
root@Linkstation :~# apt-get install locales root@Linkstation:~# dpkg-reconfigure locales root@Links ...
- .net core 2.0部署到CentOS7系统
1.Nginx的安装(重启Nginx命令: systemctl restart nginx) 输入命令( 根据提示输入Y 即可): sudo yum install epel-release sudo ...