synchronized和volatile

volatile :保证内存可见性,但是不保证原子性;

synchronized:同步锁,既能保证内存可见性,又能保证原子性;

synchronized实现可重入锁 (1.持有同一锁自动获取   2.继承锁)

锁定的对象有两种:1.类的实例(对象锁) 2.类对象(类锁)

对象锁(synchronized修饰普通方法或代码块)    对象锁已被其他调用者占用,则需要等待此锁被释放 

/**
* 对象锁的两种方式
*/
//方式一
private int count =10;
public synchronized void test01() {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
} //方式二
public void test02() {
synchronized(this) {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}

类锁(synchronized修饰静态方法)   所有类实例化对象互斥拥有一把类锁

private static int count =10;
/**
* 类锁两种表现方式
*/
public static synchronized void test01() {
count -- ;
System.out.println(Thread.currentThread().getName()+"count="+count);
} public static void test02() {
synchronized(CurrentDemo01.class) {
count -- ;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}

同一字符串常量代表同一把锁对象

//t1执行结束,t2再执行,t1和t2持有同一把锁
public class CurrentDemo03 { String s1 = "yew";
String s2 = "yew"; public void test01(){
synchronized (s1){
System.out.println(Thread.currentThread().getName()+"---start");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
System.out.println("interrupt");
}
System.out.println(Thread.currentThread().getName()+"---end");
}
} public void test02(){
synchronized (s2){
System.out.println(Thread.currentThread().getName()+"---start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("interrupt");
}
System.out.println(Thread.currentThread().getName()+"---end");
}
} public static void main(String[] args) {
CurrentDemo03 demo3 = new CurrentDemo03();
new Thread(demo3::test01,"t1").start();
new Thread(demo3::test02,"t2").start();
}
}

synchronized同步代码块粒度越小,执行效率越高

public class CurrentDemo04 {

 //总数
private static int count = 0;
public synchronized void test01() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"---start");
TimeUnit.SECONDS.sleep(2);
for (int i = 0; i <10000000 ; i++) {
count++ ;
}
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"---end");
} public void test02() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"---start");
TimeUnit.SECONDS.sleep(2);
synchronized (this){
for (int i = 0; i <10000000 ; i++) {
count++ ;
}
}
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"---end");
} //demo04.test01();8043ms
// demo04.test02();4116ms
public static void main(String[] args){
CurrentDemo04 demo04 = new CurrentDemo04();
long start = System.currentTimeMillis();
new Thread(new Runnable() {
@Override
public void run() {
try {
demo04.test02();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
demo04.test02();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
System.out.println(Thread.activeCount());
while(Thread.activeCount()>2){
Thread.yield();
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start)+"ms");
System.out.println(count);
}
}

synchronized方法正常返回或者抛异常而终止,jvm会自动释放对象锁(捕获异常则不会自动释放)

public class CurrentDemo08 {

    //总数值
private int count = 0; public synchronized void test01() throws Exception {
System.out.println(Thread.currentThread().getName()+"---start"); while (true){
count++ ;
TimeUnit.SECONDS.sleep(1);
if(count <5){
System.out.println(count);
}else{
try {
int m = count/0;
}catch (Exception e){
System.out.println("ERROR :"+e.getMessage());
// return;
}
}
}
} public synchronized void test02() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"----start"); TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"---end");
} public static void main(String[] args) { CurrentDemo08 demo08 = new CurrentDemo08(); new Thread(()-> {
try {
demo08.test01();
} catch (Exception e) {
System.out.println("test01中断");
}
},"t1").start(); new Thread(()-> {
try {
demo08.test02();
} catch (InterruptedException e) {
System.out.println("test02中断");
}
},"t2").start();
}
}
/**
* @author yew
* @date on 2019/11/18 - 11:49
* 一道面试题:实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,
* 当个数到5个时,线程2给出提示并结束线程2
* 1.无volatile,线程间不可见,线程t2不会结束
* 2.volatile可以保证原子的可见性,存在不确定性 while(true) 占用CPU资源
*/
public class CurrentDemo11 {
//List<Object> lists = new ArrayList<Object>();
volatile List<Object> lists = new ArrayList<Object>(); public void add(Object s) {
lists.add(s);
}
public int size() {
return lists.size();
} public static void main(String[] args) {
CurrentDemo11 demo11 = new CurrentDemo11(); new Thread(() -> {
for (int i = 0; i < 10; i++) {
demo11.add(new Object());
System.out.println("add Object" + (i + 1));
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1线程结束");
}, "t1").start(); new Thread(() -> {
System.out.println("t2线程开始");
while (true) {
if (demo11.size() == 5){
break;
}
}
System.out.println("t2线程结束");
}, "t2").start();
}
} 优化上述问题:
/**
* @author yew
* 1.wait----notify(随机唤醒持有当前锁且等待的某个线程)/notifyAll(唤醒持有当前锁所有的等待线程)
* notify随机唤醒持有锁等待的线程,但是不会释放当前持有的锁 所以监控线程不会立马结束
* 2.countdownLatch
*/
public class CurrentDemo12 { List lists = new ArrayList(); public int size() {
return this.lists.size();
} public void add(Object obj) {
this.lists.add(obj);
} public static void main(String[] args) {
CurrentDemo12 demo12 = new CurrentDemo12(); Object lock = new Object(); //先启用t2进行监听
new Thread(()->{
synchronized (lock){
System.out.println("t2线程启动");
if(demo12.size() != 5){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t2线程结束");
lock.notify();
} },"t2").start(); new Thread(()->{
synchronized (lock){
System.out.println("t1线程启动");
for (int i = 0; i < 10 ; i++) {
System.out.println("add Object"+(i+1));
demo12.add(new Object());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(demo12.size() == 5){
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("t1线程结束");
}
}).start();
}
}
/** * 面试题:写一个固定容量同步容器,拥有Put和get方法,以及getCount方法,
* 能够支持两个生产者线程以及10个消费者线程的阻塞调用
* wait notifyAll
*/
public class CurrentDemo13 {
private static final int MAX = 20;
private final LinkedList<Object> list = new LinkedList<>();
static int count; public synchronized void put(Object obj){
while (list.size() == MAX){
try {
this.wait();
} catch (InterruptedException e) {
System.out.println();
}
}
list.add(obj);
++count;
System.out.println("生产后剩余数量"+count);
this.notifyAll();
} public synchronized Object get(){
while (list.size()==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object t = list.removeFirst();
--count;
System.out.println("消费后剩余数量"+count);
this.notifyAll();
return t;
} public int getCount(){
return count;
} public static void main(String[] args) {
CurrentDemo13 demo13 = new CurrentDemo13();
//创建生产者
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true){
demo13.put(Thread.currentThread().getName()+"---"+count);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
} try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println(demo13.get());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
}
/**
* condition:在某种状态下
*/
public class CurrentDemo14 {
LinkedList<Object> lists = new LinkedList<>();
private static final int MAX = 20;
private static int count = 0;
ReentrantLock lock = new ReentrantLock();
Condition producer = lock.newCondition();
Condition consumer = lock.newCondition(); public void put(Object obj){ try {
lock.lock();
while (lists.size()==MAX){
producer.await();
}
lists.add(obj+"----"+count);
count++;
System.out.println("生产后剩余:"+count);
Thread.sleep(500);
consumer.signalAll();
} catch (Exception e) {
System.out.println("生产线程异常中断"+e.getMessage());
}finally {
lock.unlock();
}
} public Object get(){
Object t = null;
try {
lock.lock();
while (lists.size()==0){
consumer.await();
}
t = lists.removeFirst();
System.out.println("已消费对象:"+t);
count--;
System.out.println("消费后剩余:"+count);
Thread.sleep(2000);
producer.signalAll();
} catch (Exception e) {
System.out.println("消费线程异常中断"+e.getMessage());
}finally {
lock.unlock();
return t;
}
} public static void main(String[] args){
CurrentDemo14 currentDemo14 = new CurrentDemo14();
for (int i = 0; i < 2; i++) {
new Thread("p"+i){
public void run(){
for (;;) {
currentDemo14.put(Thread.currentThread().getName());
}
}
}.start();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
new Thread("c"+i){
public void run(){
for (;;) {
currentDemo14.get();
}
}
}.start();
}
}
}
/**
* ReentrantLock
* ReentrantLock同synchronized效果相同
* 1.synchronized遇到异常,自动释放锁,reentranLock需要手动释放锁,所以释放锁需要放在finally代码块执行;
* 2.tryLock() 尝试拿锁,拿不到锁的时候可以根据返回的boolean值来决定是否继续执行
* 3.lockInterruptibly()可以对线程中断做出反应
*/
public class CurrentDemo15 { ReentrantLock lock = new ReentrantLock(); public void test01(){
try{
lock.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"test 01");
int t = 10/0;
}catch (Exception e){
System.out.println("ERROR");
}finally {
lock.unlock();
}
} public void test02(){
try{
// lock.tryLock(3, TimeUnit.SECONDS);
// lock.lockInterruptibly();
lock.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"test 02");
}catch (Exception e){
System.out.println("ERROR");
}finally {
lock.unlock();
}
} public static void main(String[] args) {
CurrentDemo15 currentDemo15 = new CurrentDemo15();
new Thread("t1"){
public void run(){
currentDemo15.test01();
}
}.start(); try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} Thread t2 = new Thread("t2"){
public void run(){
currentDemo15.test02();
}
};
t2.start(); try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.interrupt();
}
}

synchronized和volatile使用的更多相关文章

  1. Java 线程 — synchronized、volatile、锁

    线程同步基础 synchronized 和volatile是Java线程同步的基础. synchronized 将临界区的内容上锁,同一时刻只有一个进程能访问该临界区代码 使用的是内置锁,锁一个时刻只 ...

  2. synchronized和volatile的使用

    synchronized和volatile的使用 一步一步掌握线程机制(三)---synchronized和volatile的使用 现在开始进入线程编程中最重要的话题---数据同步,它是线程编程的核心 ...

  3. java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析

    java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...

  4. java多线程之内存可见性-synchronized、volatile

    1.JMM:Java Memory Model(Java内存模型) 关于synchronized的两条规定: 1.线程解锁前,必须把共享变量的最新值刷新到主内存中 2.线程加锁时,将清空工作内存中共享 ...

  5. synchronized和volatile比较

    synchronized和volatile比较 volatile不需要加锁,比synchronized更轻量级,不会阻塞线程 从内存可见性角度讲,volatile读相当于加锁,volatile写相当于 ...

  6. java并发编程(2) --Synchronized与Volatile区别

    Synchronized 在多线程并发中synchronized一直是元老级别的角色.利用synchronized来实现同步具体有一下三种表现形式: 对于普通的同步方法,锁是当前实例对象. 对于静态同 ...

  7. synchronized与volatile的区别及各自的作用、原理(学习记录)

    synchronized与volatile的区别,它们的作用及原理? 说到两者的区别,先要了解锁提供的两种特性:互斥(mutual exclusion) 和可见性(visibility). 互斥:即一 ...

  8. synchronized和lock以及synchronized和volatile的区别

    synchronized和volatile区别synochronizd和volatile关键字区别: 1. volatile关键字解决的是变量在多个线程之间的可见性:而sychronized关键字解决 ...

  9. 对象回收过程?线程池执行过程? map原理?集合类关系?synchronized 和 volatile ? 同一个类的方法事务传播控制还有作用吗?java 锁

    1.  对象回收过程? 可达性分析算法: 如果一个对象从 GC Roots 不可达时,则证明此对象不可用. 通过一系列称为GC ROOTS的对象作为起点,从这些起点往下搜索,搜索走过的路径 称为引用链 ...

  10. Java多线程之内存可见性和原子性:Synchronized和Volatile的比较

    Java多线程之内存可见性和原子性:Synchronized和Volatile的比较     [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article ...

随机推荐

  1. /etc/profile和~/.bash_profile等文件的区别和联系

    对比说明:/etc/profile:为系统的每个用户设置环境信息和启动程序,当用户第一次登录时,该文件被执行,其配置对所有登录的用户都有效.当被修改时,必须重启才会生效.英文描述:”System wi ...

  2. 干货,Wireshark使用技巧-过滤规则

    - 过滤规则使用 在抓取报文时使用的规则,称为过滤规则,Wireshark底层是基于Winpcap,因此过滤规则是Winpcap定义的规则,设置过滤规则后,抓到的报文仅包含符合规则的报文,其它报文则被 ...

  3. [转]RHEL7上配置NFS服务

    原文地址:http://380531251.blog.51cto.com/7297595/1659865 1.课程目标 了解什么是NFS及其功能: 掌握NFS的配置: 掌握NFS的验证: 能够单独熟练 ...

  4. Python—日志模块(logging)和网络模块

    https://blog.csdn.net/HeatDeath/article/details/80548310 https://blog.csdn.net/chosen0ne/article/det ...

  5. [视频教程] docker端口映射与目录共享运行PHP

    当我们在容器中安装完环境以后,需要在宿主机的端口上访问到容器中的端口,这时候就需要做端口映射.在开发代码的时候,需要频繁的修改代码,因此要把宿主机上的代码目录共享到容器中,这样容器里面就能访问的到代码 ...

  6. [视频教程] 如何在Linux深度系统deepin下安装docker

    笔记: 安装docker的命令 curl -sSL https://get.docker.com/ | sh service docker start 排查错误的命令 strace 视频地址在此:ht ...

  7. Jinkins自动构建

    Jinkins自动构建 1.项目添加 点击左侧操作栏“新建”,填写项目基础信息,如下图: 2. General配置 2.1 丢弃旧的构建 注:此处勾选丢弃旧的构建,默认天数为1,最大个数建议填写3-5 ...

  8. 卷积层输出feature maps尺寸的计算

    默认feature maps的宽和高相等. 常规卷积 输入的feature maps尺寸为i,卷积核的尺寸为k,stride为s,padding为p,则输出的feature maps的尺寸o为 当pa ...

  9. Excel中的一列数据变成文本的一行数据

    Excel中的一列数据变成文本的一行数据 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/

  10. MongoDB高级知识(六)

    1. document的关系 多个文档之间在逻辑上可以相互联系,可以通过嵌入和引用来建立联系. 文档之间的关系可以有: 1对1 1对多 多对1 多对多 一个用户可以有多个地址,所以是一对多的关系. # ...