- 博客(20)
- 收藏
- 关注
原创 前置、JMM内存模型
由于线程对共享变量的操作都是线程拷贝到各自的工作内存进行操作后才写回到主内存中的,这就可能存在一个线程A修改了共享变量x的值,还未写回主内存时,另外一个线程B又对主内存中同一个共享变量x进行操作,但此时A线程工作内存中共享变量x对线程B来说并不可见,这种工作内存与主内存同步延迟现象就造成了可见性问题。:作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作。:作用于工作内存的变量,它把store操作从工作内存中的一个变量的值传送到主内存的变量中。
2024-02-28 10:29:12
858
原创 十五、线程池
比如,现在我的电脑只有一个CPU,如果有两个线程在同时执行找素数的任务,那么这个CPU就需要额外的进行线程上下文切换,从而达到线程并行的效果,此时执行这两个任务的总时间为:任务执行时间*2+线程上下文切换的时间。以上只是理论,实际工作中情况会更复杂,比如一个应用中,可能有多个线程池,除开线程池中的线程可能还有很多其他线程,或者除开这个应用还是一些其他应用也在运行,所以实际工作中如果要确定线程数,最好是压测。答案是会的,那有没有可能核心线程数在执行任务时都出错了,导致所有核心线程都被移出了线程池?
2024-02-26 08:51:19
821
原创 十四、并发容器
💡答:可以把容器当做一个方法来理解,方法中存在共享变量,多个线程同时执行如果要保证这个方法执行的结果没有问题,要么在方法内部添加锁,要么让使用者在执行方法的外层加锁。显然前者更合适,这就是为什么容器要加锁的原因。java集合框架中主要分为四大类别:list、set、map、queue,其中arrayList、linkedList、hashset这些都是非线程安全的。
2024-02-26 08:50:48
886
原创 十三、读锁和写锁
读读场景下不会出现线程安全问题,读写、写写场景下会出现线程安全问题。在没有写操作的时候,多个线程去读不会产生问题,但是当有一个线程想要去写操作时,就不应该有其他读线程和写线程。读写锁顾名思义就是把一把锁分为读锁和写锁两部分,读锁允许多个线程共同获得,写锁只允许一个线程获得。💡 问题:读操作为什么要加锁?在读取数据的方法中如果要那这个数据做一些业务处理,此时没有加锁被其他线程给改变了,就会造成类似于“脏读”的现象。内部维护了两个API规范,读锁和写锁。线程进入读锁的条件:线程进入写锁的条件:读写锁有以下三个
2024-02-26 08:50:14
624
原创 十二、AQS原理
AbstractQueuedSynchronizer(抽象的同步等待队列)的简称。之前讲到的ReentrantLock、Semaphore、CountDownLatch都是基于AQS来实现的。可以理解为AQS是一个抽象模板,帮我们定义了一些列的规范和工具,只需要重写其抽象方法就可以自己实现一把锁。
2024-02-25 11:22:05
803
1
原创 十一、AQS之CountDownLatch
等待指定线程执行完毕之后才开始执行,这个类使一个线程等待其他线程都执行完毕之后再执行。使通过一个计数器来实现的,计数器的初始值是线程的数量,每当一个线程执行完毕之后,调用countDown方法,计算器值减1,当计数器的值为0时,表示所有线程都执行完毕了,等待的线程就可以恢复工作了。
2024-02-25 11:21:34
278
原创 十、AQS之Semaphore
信号量Semaphore(信号量)是一种用于多线程编程的同步工具,用于控制同时访问某个资源的线程数量。它与ReentrantLock和synchronized的区别是它不是锁,但是它和锁又有着相似的地方如:资源访问的排他性。Semaphore维护了一个计数器,线程可以通过调用acquire()方法来获取Semaphore中的许可证,当计数器为0时,调用acquire()的线程将被阻塞,直到有其他线程释放许可证;
2024-02-25 11:21:04
245
原创 九、AQS之ReentrantLock
获取等待通知组件,该组件和当前的锁绑定,当前线程只有获取了锁,才能调用该组件的await()方法,而调用后,当前线程将释放锁。[阻塞] 可中断的获取锁,和lock()方法不同之处在于该方法会响应中断,即在锁的获取中可以中断当前线程。当某个线程在等待锁时,如果不想一直等待我们可以给它设置超时时间,也可以通过外部来中断等待。案例:执行装车任务,一个车道同时只允许一个车辆执行,其他车辆超时未执行要打印错误报告。可重入锁又叫递归锁,同一个线程可以重复获取同一把锁,不会因为之前的锁没有释放而阻塞。
2024-02-25 11:20:29
305
原创 六、等待唤醒方式
notify:所在的synchronized代码块全部被执行完后才会释放锁,因为在执行该方法是通知方法,只有将条件全部修改完后才会通知其他线程,所以一般该方法都会在synchronized代码块最后执行。通知一个在对象上等待的线程,使其从wait方法返回,而返回的前提是该线程获取到了对象的锁,没有获得锁的线程重新进入WAITING状态。调用该方法的线程进入 WAITING状态,只有等待另外线程的通知或被中断才会返回.需要注意,调用wait()方法后,会释放对象的锁。通知所有等待在该对象上的线程。
2024-02-25 11:18:42
416
原创 五、synchronized与volatile
但是,每个运行中的线程,如果仅仅是孤立地运行,那么没有一点儿价值,或者说价值很少,如果多个线程能够相互配合完成工作,包括数据之间的共享,协同处理事情。Java支持多个线程同时访问一个对象或者对象的成员变量,关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的。使用于一个线程写,多个线程读的场景,它能够保证每次读取都能够是最新的值,但是不能够保证读取到最新的值使用的过程中不被修改。
2024-02-25 11:18:05
236
原创 四、线程的生命周期
为什么用户线程又被称为协程呢?我们知道,内核线程的切换开销是来自于保护和恢复现场的成本, 那如果改为采用用户线程, 这部分开销就能够省略掉吗?答案还是“不能”。但是,一旦把保护、恢复现场及调度的工作从操作系统交到程序员手上,则可以通过很多手段来缩减这些开销。
2024-02-25 11:17:24
255
原创 三、线程的中断方式
不建议使用的原因主要有:以suspend()方法为例,在调用后,线程不会释放已经占有的资源(比如锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。同样,stop()方法在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资源释放工作的机会,因此会导致程序可能工作在不确定状态下。正因为suspend()、resume()和stop()方法带来的副作用,这些方法才被标注为不建议使用的过期方法。是否中断线程,如果当前线程是中断状态,会清除当前线程的中断标志,重新让当前线程状态为正常状态。
2024-02-25 11:16:47
175
原创 二、创建线程的方式
Thread类是Java里对线程概念的抽象,可以这样理解:我们通过new Thread()其实只是new出一个Thread的实例,还没有操作系统中真正的线程挂起钩来。从Thread的源码可以看到,Thread的start方法中调用了start0()方法,而start0()是个native方法,这就说明Thread#start一定和操作系统是密切相关的。start()方法让一个线程进入就绪队列等待分配cpu,分到cpu后才调用实现的run()方法,start()方法不能重复调用,如果重复调用会抛出异常(
2024-02-25 11:16:05
337
原创 一、并发编程基本概念
进程就可以视为程序的一个实例。显然,程序是死的、静态的,进程是活的、动态的。同一时刻,一个CPU核心只能运行一个线程,也就是CPU内核和同时运行的线程数是1:1的关系,也就是说8核CPU同时可以执行8个线程的代码。线程必须依赖于进程而存在,线程是进程中的一个实体,是CPU调度和分派的基本单位,它是比进程更小的、能独立运行的基本单位。这就意味着,操作系统要保证线程在调度前后的正常执行,所以,操作系统中就有上下文切换的概念,它是指CPU(中央处理单元)从一个进程或线程到另一个进程或线程的切换。
2024-02-25 11:15:09
521
原创 Mysql日志篇
的话题,假设我们把数据库所有数据都删除了要怎么恢复了,如果数据库之前没有备份,所有的binlog日志都在的话,就从binlog第一个文件开始逐个恢复每个binlog文件里的数据,这种一般不太可能,因为binlog日志比较大,早期的binlog文件会定期删除的,所以一般不可能用binlog文件恢复整个数据库的。执行自动删除距离当前15天以前的binlog日志文件的天数, 默认为0, 表示不自动删除,这个参数要结合设置的mysql备份策略来设置,如下图所示,中间不能有空挡时间,否则会丢失数据。
2024-02-25 11:05:37
720
原创 Mysql事务篇
这个隔离级别在同一个事务中,第一次查询会从数据库中获取最新的数据,并为当前数据库生成一份快照版本,在事务内之后的查询操作都是从这份快照版本中获取数据,这个时候不管其他事务怎么修改数据,当前事务中的查询结果不会受到影响,如果当前事务对某一条数据进行了更新(实际是先读取最新的值再修改快照版本中这条数据的值),那么再次查询这条数据就是修改后的值。乐观锁适合读多写少的场景,一方面是因为再此期间不会对行数据加锁,提高了并发读的能力,另一方面如果写多的场景就会发生多次update更新不成功的情况。
2024-02-25 11:03:30
1278
原创 Mysql索引篇
索引是帮助 MySQL 高效获取数据的排好序的数据结构【B+树】为什么要排好序?通过根节点去折半查找到叶子结点上的列数据。如果没有排好序无法完成折半查找,需要逐行比对。特指多字段的联合索引,索引左边的列使用了范围查找,这个时候“可能“会走索引,mysql内部会计算成本,根据计算的成本值来选择是否用索引去检索。例如 index_age_name(`age`,`name`);使用age、name两个列建立索引。
2024-02-25 11:03:06
1171
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人