synchronized

JUC学习之生产者消费者案例(Condition方式)

▼魔方 西西 提交于 2020-03-01 16:12:12
一、简介 上一篇我们介绍了使用传统的synchronized结合wait()/notifyAll()线程通信机制实现了生产者消费者案例,并且介绍了多线程交互中常见的虚假唤醒现象。我们都知道,Lock同步锁其实可以代替synchronized完成同步功能,并且使用起来还没有那么复杂,本文将介绍如何使用Lock实现生产者消费者案例。 下表是synchronized和Lock实现线程通信方法的区别: synchronized Lock wait() await() notifyAll() signalAll() Lock结合Condition可以替代synchronized实现同步功能,JDK官网介绍如下: 并且官网也给了Condition的使用示例: class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws

synchronized的可重入怎么实现。

拟墨画扇 提交于 2020-03-01 16:09:09
每个锁关联一个线程持有者和一个计数器。当计数器为0时表示该锁没有被任何线程持有,那么任何线程都都可能获得该锁而调用相应方法。当一个线程请求成功后,JVM会记下持有锁的线程,并将计数器计为1。此时其他线程请求该锁,则必须等待。而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增。当线程退出一个synchronized方法/块时,计数器会递减,如果计数器为0则释放该锁。 来源: oschina 链接: https://my.oschina.net/u/4167465/blog/3182838

简单了解下Synchronized加锁和释放锁的JVM指令

允我心安 提交于 2020-03-01 12:58:24
示例代码 public class TestMain { private Object lock = new Object ( ) ; public void get ( ) { synchronized ( lock ) { System . out . println ( "get" ) ; } } } 通过javap命令把TestMain的字节码文件反编译成JVM指令 javap - verbose TestMain . class 部分结果如下: 这里monitorexit有两个是因为线程出现异常后也会释放锁,所以monitorexit的数量会比monitorenter的数量多,无需一一对应,入口只能有一个,这是为了同步,出口可以有多个,这是为了尽量保证在不同情况下,锁都能够被顺利释放。 总结 这篇文章主要就是看下Synchronized加锁和释放锁的JVM指令是什么样的,具体细节没有做深入,可以发现 Synchronized靠的是monitorenter和monitorexit两个JVM指令配合做到加锁和释放锁的操作。 来源: CSDN 作者: 绅士jiejie 链接: https://blog.csdn.net/weixin_38106322/article/details/104578641

双从检查

拥有回忆 提交于 2020-03-01 11:53:33
一、 科普定义 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步关键字相信大家都用得比较多,在上一篇“ 多个线程之间共享数据的方式 ”中也详细列举他的应用,在这就不多说只做几点归纳: Java提供这个关键字,为防止资源冲突提供的内置支持。当任务执行到被synchronized保护的代码片段的时候,它检查锁是否可用,然后获取锁,执行代码,释放锁。 常用这个关键字可以修饰成员方法和代码块 2)读写锁 我们对数据的操作无非两种:“读”和“写”,试想一个这样的情景,当十个线程同时读取某个数据时,这个操作应不应该加同步。答案是没必要的。只有以下两种情况需要加同步: 这十个线程对这个公共数据既有读又有写 这十个线程对公共数据进行写操作 以上两点归结起来就一点就是有对数据进行改变的操作就需要同步 所以 java5提供了读写锁这种锁支持多线程读操作不互斥,多线程读写互斥,多线程写写互斥。读操作不互斥这样有助于性能的提高,这点在java5以前没有 二.用一道面试题来具体比较这两点 题目: “白板编程,实现一个缓存系统” 题目分析: 对这个缓存系统的理解: 间于用户和数据库中间的一个环节,我们知道用户直接访问数据库的时间是远大于直接访问内存,所以有了缓存区后用户访问数据时 这样,用户先访问缓存区当缓存区有用户需要的数据时直接拿走,当缓存区没有这样的数据

用Java模拟一个死锁

我的未来我决定 提交于 2020-03-01 08:38:36
模拟一个死锁:一个线程1在锁定A的过程中,需要锁定B,另一个线程2在锁定B的过程中需要锁定A,线程1想申请B 的锁已经被线程2锁定了,线程2 想申请A的锁,已经被线程1 锁定了,两个线程都无法执行,构成死锁。 public class T(){ public static String resource1="resource1"; public static String resource2="resource2"; public static void main(String[] args){ new Thread(new ClassA()).start(); new Thread(new ClassB()).start(); } } public class ClassA() implements Runnable{ public void run(){ synchronized(T.resource1){ System.out.println("得到resource1的 lock") Thread.sleep(3000); //下面请求resource2的锁 synchronized(T.resource2){ System.out.println("得到resource2 的lock") } } } } public class ClassB() implements

JAVA多线程(四)--线程同步-Volatile

好久不见. 提交于 2020-03-01 07:36:10
1.cpu cache模型 cpu - 计算机的主内存(RAM), cpu速度变快,主内存没有跟上cpu的步伐,最终导致 cpu的处理速度和主内存的访问速度差距越来越大。 而cpu cache的出现解决了以上问题,同时引入了缓存不一致的问题。 比如:i++ 1)首先读取内存到cpu cache 2)进行i+1 3)将结果刷新到主内存中 在单线程中这个例子不会出现任何问题,但是在多线程的情况下就会出现问题。原因就是:每个线程都有自己的工作内存(本地内存,对应cpu cache模型中的cache),i在多个线程的本地内存中都会存在一个副本。 例:i 初始化为0;有两个操作A和B,都执行i++操作,按道理执行完之后i的值为2,但是就会有可能出现最后的结果i为1的情况,这就是缓存不一致的问题,要解决缓存不一致,我们有以下解决方式: 1)总线加锁 cpu和其他组建通信是通过总线来进行,采用总线加锁,会阻塞其他cpu对其他组件的访问,导致只有一个cpu抢到总线锁能够访问当前数据的内存。 2)通过缓存一致性协议(MESI)保证能够保证每一个缓存中使用到的共享变量副本是一致的,大致思想就是说当cpu操作cache中 的数据时,发现该数据是共享的,会进行如下操作: a. 读取操作,不用作任何处理 b. 写入操作,发出信号通知其他cpu将该变量的cache line置为无效状态

Java Thread 锁Synchronized (一)

风流意气都作罢 提交于 2020-03-01 03:46:06
Java线程中如果给方法加锁,有一些陷井。下面用些例子进行详解 先构建一个Task类有两个执行方法 class Task { public void excute1(String threadName) { for (int i = 0; i <= 20; i++) { System.out.println(threadName + " ------ " + i); } } public void excute2(String threadName){ for (int i = 0; i <= 20; i++) { System.out.println(threadName + " ------ " + i); } } } 两个线程来分别调用Task中的excute1,excute2方法 ThreadA class ThreadA extends Thread { private Task task; public ThreadA(Task task) { this.task = task; } @Override public void run() { task.excute1(this.getName()); } } ThreadB class ThreadB extends Thread { private Task task; public ThreadB(Task

java:synchronized

徘徊边缘 提交于 2020-03-01 03:19:16
synchronized :利用上锁实现数据同步,避免多线程操作的情况下,数据出现异常。 另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。 一个线程获得了一个对象的同步锁,那这个对象上所有被同步的代码都不能执行,但不影响其他非同步代码。 在代码块前加上 synchronized关键字,则此代码块就成为同步代码块, 同步代码块:明确锁住对象 synchronized(同步对象){ 需要同步的代码; } 同步方法,跟同步代码块的功能类似:锁住的对象是this public synchronized void fun1(){ ... } 实例: class MyThread implements Runnable { int i = 100; public void run(){ while(true){ //并不是锁止状态,t1,t2同时进入 System.out.println("-------------"+Thread.currentThread().getName()); synchronized(this){ //如t1锁住,就算t2抢到cpu也进不去 System.out.println(Thread.currentThread().getName() + i); i--; if(i<0){ break; } } } } } class Test {

Java线程synchronized

一曲冷凌霜 提交于 2020-03-01 03:18:16
假设一台5个人同时要上网 每个人上时间1~5分钟不等 加锁同步情况:排队上网,每个人都在自己的上网时间完毕后出来。 静态方法同步代码 class Person extends Thread{ private Random r = new Random(); private int Num; public Person(int Num){ this.Num = Num; } public void run() { toileting(Num, r.nextInt(4) + 1); } public static synchronized void toileting(int tNo2, int time){ for (int i = 0; i < time; i++) { System.out.println("第" + tNo2 + "位, 上了" + i + "分钟"); } } } public class SetTest01 { public static void main(String[] args) { //五个人 for (int i = 0; i < 4; i++) { new Person(i).start(); } } } View Code 代码块同步代码 class Person extends Thread{ private Random r = new

锁和synchronized

与世无争的帅哥 提交于 2020-03-01 03:16:54
锁的常见概念 互斥: 同一时刻只有一个线程执行 临界区:一段需要互斥执行的代码 细粒度锁: 用不同的锁对受保护资源进行精细化管理。 细粒度锁可以提高并行度,是性能优化的一个重要手段 死锁 :一组互相竞争资源的线程因互相等待,导致“永久”阻塞的现象 。 用锁的最佳实践 永远只再更新对象的成员变量时加锁。 永远只在访问可变的成员变量时加锁。 永远不再调用其它对象的方法时加锁。 减少所得持有时间,减小锁的粒度。 同步与异步 调用方法如果需要等待结果,就是同步;如果不需要等待结果就是异步。 同步是Java代码默认的处理方式。 如何实现程序支持异步: 异步调用: 调用方创建一个子线程,再子线程中执行方法调用。 异步方法: 被调用方;方法实现的时候,创建一个显得线程执行主要逻辑,主线程直接return。 synchronized class X{ //修饰非静态方法 synchronized void foo(){ //临界区 } //修饰静态方法 synchronized static void bar(){ //临界区 } //修饰代码块 Object obj = new Object(); void baz(){ synchronized(obj){ //临界区 } } } Java编译器会在synchronized修饰的方法或代码块前后自动加上加锁lock()和解锁unlock()