学习笔记
文章平均质量分 74
韩_师兄
talk is cheap, show me the code
展开
-
关于Spring中管理Bean的杂谈
在监听器里面完成插入等操作,插入操作是通过mybatisPlus的条件构造器完成的,需要注入自定义的SubjectService来完成,但是直接在监听器里使用@Auwowired注入subjectService,会报空指针。原因如下:首先要区分Listener的生命周期和spring管理的bean的生命周期。原创 2024-02-20 10:44:01 · 411 阅读 · 0 评论 -
关于StringJoiner的使用
在项目中,经常有某些集合数据,需要添加逗号或其他符号,拼接成字符串展示,而普通的遍历后追加分隔符,需要单独处理最后一个元素,比较繁琐.Java8中,提供了一个工具类,即StringJoiner可以完美解决此类问题.StringJoiner类, 是Java8中,java.util包下的一个类.基于StringBuilder实现.主要用于对字符串通过分隔符进行拼接的场景.: 长度,如value为null则返回空值长度。: 合并另一个StringJoiner。: 构建准备,不存在则新增。原创 2023-10-24 11:44:43 · 268 阅读 · 0 评论 -
关于在集合中对象比较属性值的问题
数据库查询的集合对象与前端传递的集合对象进行比较原创 2023-02-13 21:31:25 · 490 阅读 · 1 评论 -
关于Git中代码代码push出现index. lock问题
Git 执行操作时会自动生成 index.lock 文件,操作结束后会自动删除, 上锁的主要是为了避免同时操作同一个文件夹。找到对应的.git目录层级, 删除掉相关的index.lock文件.1 双击我的电脑(此电脑)原创 2022-09-27 21:47:30 · 1576 阅读 · 0 评论 -
多线程之JUC队列与数组
Tomcat 的 Connector 结构时,Acceptor 作为生产者向 Poller 消费者传递事件信息时,正是采用了 ConcurrentLinkedQueue 将 SocketChannel 给 Poller 使用.CopyOnWriteArraySet 是它的马甲 底层实现采用了 写入时拷贝 的思想,增删改操作会将底层数组拷贝一份,更 改操作在新数组上执行,这时不影响其它线程的并发读,读写分离。在线程0读取数组, 线程1读取数组, 然后线程1去删除数组元素,线程0任然可以读取数据.原创 2022-09-25 10:09:25 · 398 阅读 · 0 评论 -
多线程之ConcurrentHashMap原理
此外, JDK 8 虽然将扩容算法做了调整,不再将元素加入链表头(而是保持与扩容前一样的顺序),但仍不意味着能 够在多线程环境下能够安全扩容,还会出现其它问题(如扩容丢数据)因为 Thread-1 扩容时链表也是后加入的元素放入链表头,因此链表就倒过来了,但 Thread-1 虽然结 果正确,但它结束后 Thread-0 还要继续运行。断点的条件如下,目的是让 HashMap 在扩容为 32 时,并且线程为 Thread-0 或 Thread-1 时停下来。HashMap 的并发死链发生在扩容时.原创 2022-09-15 08:13:18 · 362 阅读 · 0 评论 -
多线程之线程安全集合类
线程安全集合类可以分为三大类:遗留的线程安全集合如 Hashtable , Vectorjava.util.concurrent.*包下面类。原创 2022-08-25 07:29:21 · 545 阅读 · 0 评论 -
多线程之CountdownLatch应用
从运行结果来看, 都是两秒后,线程才继续往下执行,即当CyclicBarrier线程等于设置值时,才能向下执行后续操作. 当CyclicBarrier归零后, 又恢复设置值, 即可重用机制. ( CountDownLatch没有可重用机制, 类似一次性工具,使用后即功能失效)构造时设置『计数个数』,每个线程执 行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续执行.在平常的微服务项目中, 都是通过feign接口,互相调用不同业务的模块,涉及到多个远程调用.原创 2022-08-24 21:04:46 · 962 阅读 · 0 评论 -
多线程之CountdownLatch
构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一.CountdownLatch, 用来进行线程同步协作,等待所有线程完成倒计时.原创 2022-08-23 12:13:11 · 294 阅读 · 0 评论 -
多线程之Semaphore原理
Thread-0 竞争成功,permits 再次设置为 0,设置自己为 head 节点,断开原来的 head 节点,unpark 接 下来的 Thread-3 节点,但由于 permits 是 0,因此 Thread-3 在尝试不成功后再次进入 park 状态。3 T4 调用 releaseShared(1),此时 head.waitStatus 为 0(此时读到的 head 和 1 中为同一个head),不满足条件,因此不调用 unparkSuccessor(head)原创 2022-08-22 19:28:04 · 231 阅读 · 0 评论 -
多线程之Semaphore
Semaphore 限流,在访问高峰期时,让请求线程阻塞,高峰期过去再释放许可,当然它只适合限制单机 线程数量,并且仅是限制线程数,而不是限制资源数.Semaphore 实现简单连接池,对比『享元模式』下的实现(用wait notify),性能和可读性显然更好.Semaphore 信号量,用来限制能同时访问共享资源的线程上限.原创 2022-08-21 09:06:28 · 271 阅读 · 0 评论 -
多线程之 StampedLock
是为了进一步优化读性能,它的特点是在使用读锁、写锁时都必须配合【戳】使用加解读锁加解写锁乐观读,StampedLock 支持 tryOptimisticRead() 方法(乐观读),读取完毕后需要做一次 戳校验 如果校验通 过,表示这期间确实没有写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据安全.// 验戳 if(!// 锁升级 }原创 2022-08-20 08:14:44 · 142 阅读 · 0 评论 -
读写锁原理
进入 sync.doAcquireShared(1) 流程,首先也是调用 addWaiter 添加节点,不同之处在于节点被设置为 Node.SHARED 模式而非 Node.EXCLUSIVE 模式,注意此时 t2 仍处于活跃状态。t3 进入 sync.releaseShared(1) 中,调用 tryReleaseShared(1) 让计数减一,这回计数为零了,进入 doReleaseShared() 将头节点从 -1 改为 0 并唤醒老二,即。0 表示成功,但后继节点不会继续唤醒。原创 2022-08-19 16:46:13 · 429 阅读 · 0 评论 -
读写锁之ReentranReadWriteLock
如存在一个数据容器类内部分别使用读锁保护数据的 read() 方法,写锁保护数据的 write() 方法.当读操作远远高于写操作时,这时候使用 读写锁 让 读-读 可以并发,提高性能.从结果看,线程读写是互相阻塞的.从结果看,线程读没有互相影响....原创 2022-08-18 19:52:40 · 155 阅读 · 0 评论 -
ReentrantLock原理之公平锁原理
开始 Thread-0 持有锁,调用 await,进入 ConditionObject 的 addConditionWaiter 流程 创建新的 Node 状态为 -2(Node.CONDITION),关联 Thread-0,加入等待队列尾部。执行 transferForSignal 流程,将该 Node 加入 AQS 队列尾部,将 Thread-0 的 waitStatus 改为 0,Thread-3 的 waitStatus 改为 -1。Thread-1 释放锁,进入 unlock 流程....原创 2022-08-17 21:00:27 · 278 阅读 · 0 评论 -
ReentrantLock原理之非公平锁
是否需要 unpark 是由当前节点的前驱节点的 waitStatus == Node.SIGNAL 来决定,而不是本节点的 waitStatus 决定。当前队列不为 null,并且 head 的 waitStatus = -1,进入 unparkSuccessor 流程。找到队列中离 head 最近的一个 Node(没取消的),unpark 恢复其运行,即为 Thread-1。Thread-0 释放锁,进入 tryRelease 流程,如果成功,会做两件事。多个线程竞争失败,变成如下图列。...原创 2022-08-16 19:25:03 · 427 阅读 · 0 评论 -
AQS原理
AQS 是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取 锁和释放锁getState - 获取 state 状态setState - 设置 state 状态compareAndSetState - cas 机制设置 state 状态独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源。...原创 2022-08-15 19:44:39 · 166 阅读 · 0 评论 -
Tomcat线程池与Fork/Join使用
LimitLatch 用来限流,可以控制最大连接个数Acceptor 只负责接收新的 socket 连接Poller 只负责监听 socket channel 是否有可读的 I/O 事件一旦可读,封装一个任务对象(socketProcessor),提交给 Executor 线程池处理Executor 线程池中的工作线程最终负责进行处理请求。...原创 2022-08-14 14:45:12 · 394 阅读 · 0 评论 -
多线程之任务调度线程池
使用任务调度线程池, 可以使用 java.util.Timer 来实现定时功能.Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个 任务的延迟或异常都将会影响到之后的任务。线程数固定,任务数多于线程数时,会放入无界队列排队。2 由于 timer 内只有一个线程来顺序执行队列中的任务,因此『任务1』的延时,影响了『任务2』的执行。说明: 一开始,延时 1s,接下来,由于任务执行时间 > 间隔时间,间隔被『撑』到了 2s....原创 2022-08-13 14:30:02 · 887 阅读 · 0 评论 -
多线程之异步模式工作线程
让有限的工作线程(Worker Thread)来轮流异步处理无限多的任务。也将其归类为分工模式,它的典型实现就是线程池,也体现在经典设计模式中的享元模式上.原创 2022-08-12 18:19:34 · 306 阅读 · 0 评论 -
多线程之ThreadPoolExecutor相关
希望多个任务排队执行。线程数固定为 1,任务数多于 1 时,会放入无界队列排队。任务执行完毕,这唯一的线程也不会被释放.根据ThreadPoolExecutor的构造方法,JDK提供了很多工厂方法来创建各种用途的线程池.整个线程池表现为线程数会根据任务量不断增长,没有上限,当任务执行完毕,空闲 1分钟后释放线程。上述都是提供的提交任务的方法,根据不同的业务场景需求,选择对应的提交方法.任务数比较密集,但每个任务执行时间较短的情况。任务量一已知,相对耗时的任务。...原创 2022-08-11 20:35:37 · 300 阅读 · 0 评论 -
多线程之ThreadPoolExecutor
当高峰过去后,超过corePoolSize 的救急线程如果一段时间没有任务做,需要结束节省资源,这个时间由 keepAliveTime 和 unit 来控制。当线程数达到 corePoolSize 并没有线程空闲,这时再加入任务,新加的任务会被加入workQueue 队列排 队,直到有空闲的线程。信息存储在一个原子变量 ctl 中,目的是将线程池状态与线程个数合二为一,这样就可以用一次 cas 原子操作 进行赋值。线程池中刚开始没有线程,当一个任务提交给线程池后,线程池会创建一个新线程来执行任务。...原创 2022-08-10 21:27:55 · 271 阅读 · 0 评论 -
多线程之自定义线程池
1 自义定线程池1定义2 组成部分自定义线程池组成部分: 核心线程数,等待超时时间,等待时间单位,任务队列,拒绝策略.原创 2022-08-09 21:19:36 · 718 阅读 · 0 评论 -
多线程之享元模式和final原理
享元模式,Flyweight pattern, 当需要重用数量有限的同一类对象时使用.原创 2022-08-08 21:28:25 · 290 阅读 · 2 评论 -
多线程之不可变对象
SimpleDateFormat是线程不安全类,在对线程环境下,会出现错误.出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果.2 解决方案1 同步锁加锁 ,保证每次只有一个线程去执行方法. 能解决问题,但是影响性能效率.2 类不可变如果一个对象在不能够修改其内部状态(属性),那么它就是线程安全的,因为不存在并发修改.以Java8提供的新日期格式化类DateTimeFormatter.将对象置为不可变对象,是一种避免竞争的方式.String类型就原创 2022-08-07 16:38:47 · 188 阅读 · 0 评论 -
多线程之原子数组
性能提升的原因,是在有竞争时,设置多个累加单元,Therad-0 累加 Cell[0],而 Thread-1 累加 Cell[1]…这样它们在累加时操作的不同的 Cell 变量,因此减少了 CAS 重试失败,从而提高性能.利用字段更新器,可以针对对象的某个域(Field)进行原子操作,只能配合 volatile 修饰的字段使用,否则会出现下列异常。...原创 2022-08-06 14:06:14 · 194 阅读 · 0 评论 -
多线程之原子整数和原子引用
AtomicStampedReference 可以给原子引用加上版本号,追踪原子引用整个的变化过程,如: A -> B -> A -> C ,通过AtomicStampedReference,我们可以知道,引用变量中途被更改了几次.如果主线程希望, 只要有其它线程 变动过 共享变量,那么自己的 cas 就算失败,这时,需要再加一个版本号.主线程仅能判断出共享变量的值与最初值 A 是否相同,不能感知到这种从 A 改为 B 又 改回 A 的情况。但有时候,不关心变量更改过几次,只关心是否被更改过.使用到。...原创 2022-08-05 20:14:15 · 182 阅读 · 0 评论 -
并发之CAS
1 无锁效率高无锁情况下,即使重试失败,线程始终在高速运行,没有停歇,而 synchronized 会让线程在没有获得锁的时 候,发生上下文切换,进入阻塞. 但无锁情况下,因为线程要保持运行,需要额外 CPU 的支持, 但由于没有分到时间片,仍然会进入可运行状态,还是会导致上下文切换.2 CAS特点CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,再重试获取值。...原创 2022-08-04 10:28:45 · 170 阅读 · 0 评论 -
线程之Happens-before规则
happens-before 规定了对共享变量的写操作对其它线程的读操作可见,它是可见性与有序性的一套规则总结,抛开以下 happens-before 规则,JMM 并不能保证一个线程对共享变量的写,对于其它线程对该共享变量的读可见.线程解锁 m 之前对变量的写,对于接下来对 m 加锁的其它线程对该变量的读可见。对变量默认值(0,false,null)的写,对其它线程对该变量的读可见。线程对 volatile 变量的写,对接下来其它线程对该变量的读可见。...原创 2022-08-03 08:12:55 · 149 阅读 · 0 评论 -
内存模型之有序性
在0getstatic这行代码在monitor控制之外,它就像之前举例中不守规则的人,可以越过monitor读取INSTANCE变量的值,此时t1还未完全将构造方法执行完毕,如果在构造方法中要执行很多初始化操作,那么t2拿到的是将是一个未初始化完毕的单例.(存在问题)读屏障(lfence)保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据。写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中。可借助Java并发压测工具jcstress工具。...原创 2022-08-02 07:47:35 · 231 阅读 · 0 评论 -
内存模型之可见性
Balking(犹豫)模式用在一个线程发现另一个线程或本线程已经做了某一件相同的事,那么本线程就无需再做了,直接结束返回。原创 2022-08-01 08:25:24 · 445 阅读 · 0 评论 -
并发之固定运行和交替运行方案
列如,线程1输出a5次,线程2输出b5次,线程3输出c5次。1需要保证先wait再notify,否者wait线程永远都不能唤醒.所以上面添加了标识来判断是否wait.2如存在干扰线程错误notify了wait线程,条件标识不满足需要重新等待,添加了while循环控制.3唤醒对象上的wait线程需要使用notifyAll,同步线程可能存在多个.1他俩谁先调用,谁后调用无所谓。2是以线程为单位进行暂停和恢复。例如,按规定先输出2再输出1。...原创 2022-07-31 10:19:55 · 167 阅读 · 0 评论 -
并发之ReentrantLock
synchronized中也有条件变量,ReentrantLock的条件变量比synchronized强大之处在于,它是支持多个条件变量的.指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住.保证每次执行,且总在最后输出.公平锁一般没有必要,并且会降低并发度.与synchronized相同点,都支持可重入.ReentrantLock默认是不公平的.创建对象时,将对象设置为true....原创 2022-07-28 21:20:50 · 226 阅读 · 0 评论 -
并发之多把锁和活跃性
线程1和线程2,都要同时去获取对象A和对象B锁,结果线程1获取到对象A锁,线程2获取到对象B锁,互相再向下进行,就互相尝试获取锁,发生死锁.规定加锁的顺序,当线程1和线程2,同时竞争对象锁A,仅有一个线程成功后,才能去竞争对象锁B,不然就阻塞,此时可以解决死锁问题.t1线程获得A对象锁,接下来想获取B对象的锁t2线程获得B对象锁,接下来想获取A对象的锁.说明,将锁的粒度细分,好处是可以增加并发度,坏处是如果一个线程需要获取多把锁,容易造成死锁。...原创 2022-07-27 20:59:20 · 193 阅读 · 0 评论 -
并发之线程状态转换
当前线程等待时间超过了n毫秒,或t线程运行结束,或调用了当前线程的interrupt()时,当前线程从TIMED_WAITING-->RUNNABLE。调用LockSupport.unpark(目标线程)或调用了线程的interrupt(),会让目标线程从WAITING-->RUNNABLE。t线程运行结束,或调用了当前线程的interrupt()时,当前线程从WAITING-->RUNNABLE。当前线程所有代码运行完毕,进入TERMINATED。...原创 2022-07-26 21:42:02 · 125 阅读 · 0 评论 -
并发之park与unpark说明
park&unpark是以线程为单位来【阻塞】和【唤醒】线程,而notify只能随机唤醒一个等待线程,notifyAll是唤醒所有等待线程,就不那么【精确】每个线程都有自己的一个Parker对象,由三部分组成_counter,_cond和_mutex.1调用Unsafe.unpark(Thread_0)方法,设置_counter为1。1调用Unsafe.unpark(Thread_0)方法,设置_counter为1。4设置_counter为0。...原创 2022-07-25 08:19:52 · 290 阅读 · 0 评论 -
并发之wait/notify说明
obj.wait() 让进入 object 监视器的线程到 waitSet 等待obj.notify() 在 object 上正在 waitSet 等待的线程中挑一个唤醒**(随机)**obj.notifyAll() 让 object 上正在 waitSet 等待的线程全部唤醒第一次测试notify结果第二次测试notifyAll结果wait() 方法会释放对象的锁,进入 WaitSet 等待区,从而让其他线程就机会获取对象的锁。无限制等待,直到 notify 为止.sleep(long n)和wai原创 2022-06-27 22:08:15 · 174 阅读 · 0 评论 -
并发之Synchronized说明
Java对象头以32位虚拟机为例:普通对象数组对象其中Mark Word结构一般组成为:25位 hashcode + 分代年龄(经过几次回收仍存在再移至老年代) + 是否启用偏向锁(0否 1是)+加锁标识信息Monitor, 又称监视器或管程.每个Java对象都可以关联一个Monitor对象,如果Synchronized给对象上锁(重量级)之后, 该对象头的Mark Word中设置就指向Monitor对象的指针说明:使用场景:如果一个对象虽然有多线程要加锁,但加锁的时间是错开的(也就是没有竞争),那么可以原创 2022-06-26 14:33:08 · 254 阅读 · 0 评论 -
并发之线程安全
局部变量线程安全分析每个线程调用 test1() 方法时局部变量 i,会在每个线程的栈帧内存中被创建多份,因此不存在共享.成员变量说明:解决方法将list改为局部变量说明:String, Integer, StringBuffer, Random, Vector, Hashtable, java.util.concurrent包下的类多个线程调用它们同一个实例的某个方法时,是线程安全的,即说明:线程安全类方法的组合不可变类线程安全String、Integer 等都是不可变类,因为其内部的状态不可原创 2022-06-25 22:38:32 · 315 阅读 · 0 评论 -
并发之共享模型管程
两个线程对同一个数进行了加和减的操作,因为上下文切换,导致值没能更新,从而影响统计的结果.问题说明以上的结果可能是正数、负数、零.因为 Java 中对静态变量的自增,自减并不是原子操作,从字节码来分析对于i++操作,对应JVM字节码对于i–操作Java 的内存模型如下,完成静态变量的自增,自减需要在主存和工作内存中进行数据交换:在单线程中执行,没有问题;在多线程中,可能出现正数,负数.临界区以下为例:竞态条件多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,即发生了竞态条件为了避免临原创 2022-06-24 08:17:56 · 181 阅读 · 0 评论