原子性提供了互斥访问:同一时刻只能有一个线程进行操作;

除了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锁的更多相关文章

  1. Java并发编程入门与高并发面试(三):线程安全性-原子性-CAS(CAS的ABA问题)

    摘要:本文介绍线程的安全性,原子性,java.lang.Number包下的类与CAS操作,synchronized锁,和原子性操作各方法间的对比. 线程安全性 线程安全? 线程安全性? 原子性 Ato ...

  2. 4-3 线程安全性-原子性-synchronized

    原子性它提供了互斥访问,同一时刻只能有一个线程来对它进行操作.能保证同一时刻只有一个线程来对其进行操作的,除了Atomic包之外,还有锁.JDK提供锁主要分两种,synchronized是一个Java ...

  3. 并发与高并发(八)-线程安全性-原子性-synchronized

    前言 闲暇时刻,谈一下曾经在多线程教程中接触的同步锁synchronized,相当于复习一遍吧. 主要介绍 synchronized:依赖JVM Lock:依赖特殊的CPU指令,代码实现,Reetra ...

  4. 并发与高并发(七)-线程安全性-原子性-atomic

    一.线程安全性定义 定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程 ...

  5. 线程安全性-原子性之Atomic包

    先了解什么是线程安全性:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称为这个类是线程 ...

  6. java多线程中篇(二) —— 线程的创建和Synchronized锁关键字

    学习之前,先了解线程状态图 说明:线程共包括以下5种状态. 1. 新建状态(New)         : 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread ...

  7. 4-2 线程安全性-原子性-atomic-2

    AtomicReference和AtomicLong.AtomicInteger很像,方法也基本上是一样的,然后我们通过引用Integer来做一个简单的例子. com.mmall.concurrenc ...

  8. Java线程安全性-原子性工具对比

    synchronized 不可中断锁,适合竞争不激烈的场景,可读性好,竞争激烈时性能下降很快 Lock 可中断锁,多样化同步,竞争激烈时能维持常态 Atomic 竞争激烈时能维持常态,比Lock性能还 ...

  9. 4-1 线程安全性-原子性-atomic-1

    我们发现在不做任何同步的情况下,我们计算的累加结果是错误的. com.mmall.concurrency.example.count.CountExample2 C:\Users\ZHONGZHENH ...

随机推荐

  1. 动态div点击事件传递对象参数格式-草稿889

    <button type='button' style='border: 1px solid #eeeeee;color: #717070;height: 20px;border-radius: ...

  2. C++---使用类

    运算符重载 概念 运算符重载就是想法转换, 目的是简化函数调用的方式 重载就是赋予新的含义, 运算符重载也是, 即同一个运算符可以有不同的功能 C++本身已经对一些运算符进行了重载, 同时C++允许程 ...

  3. python循环与基本数据类型内置方法

    今天又是充满希望的一天呢 一.python循环 1.wuile与else连用 当while没有被关键'break'主动结束的情况下 正常结束循环体代码之后会执行else的子代码 "" ...

  4. SQLite 数据库使用记录

    SQLite 数据库使用记录 官网 https://www.sqlite.org/index.html 下载地址 https://www.sqlite.org/download.html 参考资料 S ...

  5. 帝国CMS模板$GLOBALS[navclassid]用法详解

    帝国CMS模板程序扩展变量说明:通过这些变量可实现各种更复杂的显示格式. 一.列表/封面模板变量说明:(栏目页或专题页中使用) (一).当前栏目ID或专题ID:$GLOBALS[navclassid] ...

  6. @RequestBody和@RequestParam注解以及返回值,ajax相关知识点

    关于前后端传递json数据这块查了好多资料,好多地方还是不清楚,先记录一下清楚的地方. 如果我们前端使用ajax发json数据,一般都加上contentType:'application/json;c ...

  7. C++怎么实现多态?

    C++通过函数重载或模板实现编译期多态(静态绑定),通过虚函数实现运行时多态(动态绑定). 1.函数重载 #include <stdio.h> int add(int a, int b) ...

  8. 将个人项目发布到mavan中央仓库

    第一步,准备自己的git代码 比如在gitee或者github上的代码,我的是gitee码云上的,开源了一个处理业务日志采集的组件,支持注解方式,支持SpEL表达式,支持变量自定义. 话不多说,直接上 ...

  9. 反射解决微信开发加解密illegal key size,不需要修改JDK jar包

    在微信开发时,消息接口时,涉及到消息加密,抛出了 java.security.InvalidKeyException: Illegal key size 的异常,异常堆栈如下: 按照网上的解决方案,都 ...

  10. springmvc-02(配置版与注解版区别)

    首先,我们来看配置版和注解版的相同步骤: 1.新建一个Moudle , springmvc-02-hello , 添加web的支持! 2.确定导入了SpringMVC 的依赖! 3.配置web.xml ...