线程安全性-原子性之synchronized锁
原子性提供了互斥访问:同一时刻只能有一个线程进行操作;
除了Atomic包类之外,还有锁可以实现此功能;
synchronized: java关键字,依赖于jvm实现锁功能,被此关键字所修饰的,都是在同一时刻,只能有一个线程操作;
Lock: 由jdk提供的锁,Lock类,比如ReentranLock等..;
这次针对synchronized进行介绍:synchronized是一种同步锁,修饰对象有四种;
一,修饰代码块:大括号括起来的代码,作用于调用的对象,被修饰的代码称为同步语句块。
二,整个方法,作用于调用的对象,被修饰的方法称为同步方法。
三,整个静态方法,作用于所有对象。
四,修饰类,synchronized后面括号括起来的部分,作用于所有对象。
package com.example.concurrency.example.sync;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author xiaozhuang
* @date 2022年04月08日 14:47
*/
@Slf4j
public class SynchronizedExample1 {
// 修饰代码块 作用于调用的对象
public void test1(){
synchronized (this){
for (int i = 0; i < 3; i++) {
log.info("修饰代码块:{}",i);
}
}
}
public static void main(String[] args) {
SynchronizedExample1 synchronizedExample1=new SynchronizedExample1();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(()->{
synchronizedExample1.test1();
});
executorService.execute(()->{
synchronizedExample1.test1();
});
executorService.shutdown();
}
}
先看看修饰代码块的例子,它是作用于调用的对象,这里我们根据对象 在线程池中调用了2次,test1方法,看一下输出

再改为两个对象调用时


发现它是交替按顺序输出的,它是作用于调用对象,所以不用对象调用之间是相互不影响的,在上面一个对象调用两次test1方法,则是需要一个执行完再执行另一个。
再看看修饰方法,也是作用于调用对象:


再看看两个对象调用时

可以看到输出是与上面的修饰代码块是一样;
可以得出一个结论:如果一个方法内部一整个都是同步代码块,那么它与用synchronized修饰的方法是等同的。
如果当前类是父类,当子类继承父类时,调用父类被synchronized修饰的方法时,是不会带上synchronized关键字的,需要自己手动加上去,synchronized不属于方法声明部分;
再看看修饰静态方法与修饰类的:


这里因为修饰类与修饰静态方法的作用于所有的对象,所以在这个类里,都是需要逐个执行完毕;
结论:如果一个方法里,一整个都是被synchronized所修饰的类包围的时候,那么它与被synchronized修饰的静态方法的作用是等同的。
通过上面对synchronized的了解,所以一个计数的问题也就迎刃而解了;
@Slf4j
public class ConcurrencyTest {
// 请求访问总数
public static int clientTotal = 5000;
// 同时并发执行的线程数
public static int threadTotal = 200;
// 计数的值
public static int count = 0;
public static void main(String[] args) throws InterruptedException {
// 线程池
ExecutorService executorService = Executors.newCachedThreadPool();
// 信号量 参数为 运行并发的数目
final Semaphore semaphore = new Semaphore(threadTotal);
// 递减计数器 参数为 请求数量 没执行成功一次会 减1
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal; i++) {
// 讲请求放入线程池中
executorService.execute(() -> {
try {
//判断信号量 判断当前线程是否允许被执行
semaphore.acquire();
add();
// 释放进程
semaphore.release();
} catch (Exception e) {
log.error("exception", e);
}
// 没执行完一次 计算器-1
countDownLatch.countDown();
});
}
countDownLatch.await();
// 关闭线程池
executorService.shutdown();
log.info("count:{}", count);
}
private static void add() {
count++;
}
}
只需要在add()方法加上synchronized,就会变成线程安全了;
最后对比一下synchronized,Lock,Atomic三者的区别:
synchronized:在执行到synchronized作用范围内的时候,它是不可中断的,必须等待代码执行完毕。适合竞争不激烈,可读性好,竞争激烈时,性能下降较快;
Lock:是可以中断的,只需要调用unLock就行,多样化同步,竞争激烈时能维持常态;
Atomic: 竞争激烈时能维持常态,比Lock性能好; 缺点就是只能同步一个值;
线程安全性-原子性之synchronized锁的更多相关文章
- Java并发编程入门与高并发面试(三):线程安全性-原子性-CAS(CAS的ABA问题)
摘要:本文介绍线程的安全性,原子性,java.lang.Number包下的类与CAS操作,synchronized锁,和原子性操作各方法间的对比. 线程安全性 线程安全? 线程安全性? 原子性 Ato ...
- 4-3 线程安全性-原子性-synchronized
原子性它提供了互斥访问,同一时刻只能有一个线程来对它进行操作.能保证同一时刻只有一个线程来对其进行操作的,除了Atomic包之外,还有锁.JDK提供锁主要分两种,synchronized是一个Java ...
- 并发与高并发(八)-线程安全性-原子性-synchronized
前言 闲暇时刻,谈一下曾经在多线程教程中接触的同步锁synchronized,相当于复习一遍吧. 主要介绍 synchronized:依赖JVM Lock:依赖特殊的CPU指令,代码实现,Reetra ...
- 并发与高并发(七)-线程安全性-原子性-atomic
一.线程安全性定义 定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程 ...
- 线程安全性-原子性之Atomic包
先了解什么是线程安全性:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称为这个类是线程 ...
- java多线程中篇(二) —— 线程的创建和Synchronized锁关键字
学习之前,先了解线程状态图 说明:线程共包括以下5种状态. 1. 新建状态(New) : 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread ...
- 4-2 线程安全性-原子性-atomic-2
AtomicReference和AtomicLong.AtomicInteger很像,方法也基本上是一样的,然后我们通过引用Integer来做一个简单的例子. com.mmall.concurrenc ...
- Java线程安全性-原子性工具对比
synchronized 不可中断锁,适合竞争不激烈的场景,可读性好,竞争激烈时性能下降很快 Lock 可中断锁,多样化同步,竞争激烈时能维持常态 Atomic 竞争激烈时能维持常态,比Lock性能还 ...
- 4-1 线程安全性-原子性-atomic-1
我们发现在不做任何同步的情况下,我们计算的累加结果是错误的. com.mmall.concurrency.example.count.CountExample2 C:\Users\ZHONGZHENH ...
随机推荐
- 动态div点击事件传递对象参数格式-草稿889
<button type='button' style='border: 1px solid #eeeeee;color: #717070;height: 20px;border-radius: ...
- C++---使用类
运算符重载 概念 运算符重载就是想法转换, 目的是简化函数调用的方式 重载就是赋予新的含义, 运算符重载也是, 即同一个运算符可以有不同的功能 C++本身已经对一些运算符进行了重载, 同时C++允许程 ...
- python循环与基本数据类型内置方法
今天又是充满希望的一天呢 一.python循环 1.wuile与else连用 当while没有被关键'break'主动结束的情况下 正常结束循环体代码之后会执行else的子代码 "" ...
- SQLite 数据库使用记录
SQLite 数据库使用记录 官网 https://www.sqlite.org/index.html 下载地址 https://www.sqlite.org/download.html 参考资料 S ...
- 帝国CMS模板$GLOBALS[navclassid]用法详解
帝国CMS模板程序扩展变量说明:通过这些变量可实现各种更复杂的显示格式. 一.列表/封面模板变量说明:(栏目页或专题页中使用) (一).当前栏目ID或专题ID:$GLOBALS[navclassid] ...
- @RequestBody和@RequestParam注解以及返回值,ajax相关知识点
关于前后端传递json数据这块查了好多资料,好多地方还是不清楚,先记录一下清楚的地方. 如果我们前端使用ajax发json数据,一般都加上contentType:'application/json;c ...
- C++怎么实现多态?
C++通过函数重载或模板实现编译期多态(静态绑定),通过虚函数实现运行时多态(动态绑定). 1.函数重载 #include <stdio.h> int add(int a, int b) ...
- 将个人项目发布到mavan中央仓库
第一步,准备自己的git代码 比如在gitee或者github上的代码,我的是gitee码云上的,开源了一个处理业务日志采集的组件,支持注解方式,支持SpEL表达式,支持变量自定义. 话不多说,直接上 ...
- 反射解决微信开发加解密illegal key size,不需要修改JDK jar包
在微信开发时,消息接口时,涉及到消息加密,抛出了 java.security.InvalidKeyException: Illegal key size 的异常,异常堆栈如下: 按照网上的解决方案,都 ...
- springmvc-02(配置版与注解版区别)
首先,我们来看配置版和注解版的相同步骤: 1.新建一个Moudle , springmvc-02-hello , 添加web的支持! 2.确定导入了SpringMVC 的依赖! 3.配置web.xml ...