多线程相关
1.java中创建线程的方式
继承thread类,重写run()方法 实现runable接口,重写run()方法,避免了单继承的局限性 实现callable接口,重写call()方法,这个有放回值
2.线程的几种状态
线程在一定条件下,状态会发生变化。线程一共有以下几种状态:
1、新建状态(New) :新创建了一个线程对象。
2、就绪状态(Runnable) :线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的进程除 CPU之外,其它的运行所需资源都已全部获得。
3、运行状态(Running): 就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
阻塞的情况分三种:
(1)、等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“等待池” 中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,
(2)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入 “锁池” 中。
(3)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead): 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
3.谈谈线程死锁,如何有效的避免线程死锁?
运行两个或多个线程时,由于同时持有相互需要的锁对象,造成线程进入阻塞状态,谁都无法继续继续,造成死锁
避免造成死锁,1是尽量不要使用嵌套锁,2是使用定时锁 ReentrantLock
4.如何实现多线程中的同步
synchronized (同步非静态方法或同步代码块,同步的静态方法会锁住整个类) lock(lock unlock,必须在finally里调用unlock()释放锁,否则会造成死锁) volatile a.volatile关键字为域变量的访问提供了一种免锁机制,
b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,
c.因此每次使用该域就要重新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量
//需要同步的变量加上volatile
private volatile int account = 100;
5.synchronized和Lock的使用、区别,原理;
使用见问题四 区别: 1.sync时关键字,lock是接口 2.在线程异常时,sync会自动释放锁,不会因此导致死锁,而lock不会自动释放锁,必须在finally手动释放(unlock),不然可能会导致死锁 3.通过lock可以知道有没有获取成功锁(trylock()方法),sync办不到 4.Lock可以提高多个线程进行读操作的效率。 5.在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
6.volatile,synchronized和volatile的区别?为何不用volatile替代synchronized?
vilatile,是关键字,为了让变量在发生改变时尽快让其他线程知道
原理:当对volatile标记的变量进行修改时,会将其他缓存中存储的修改前的变量清除,然后重新读取。一般来说应该是先在进行修改的缓存A中修改为新值,然后通知其他缓存清除掉此变量,当其他缓存B中的线程读取此变量时,会向总线发送消息,这时存储新值的缓存A获取到消息,将新值穿给B。最后将新值写入内存。当变量需要更新时都是此步骤,volatile的作用是被其修饰的变量,每次更新时,都会刷新上述步骤。
区别:synchronized 是独占锁/排他锁(就是有你没我的意思),同时只能有一个线程调用 add10KCount
方法,其他调用线程会被阻塞。所以三行 CPU 指令都是同一个线程执行完之后别的线程才能继续执行,这就是通常说说的 原子性 (线程执行多条指令不被中断)
但 volatile 是非阻塞算法(也就是不排他),当遇到三行 CPU 指令自然就不能保证别的线程不插足了,这就是通常所说的,volatile 能保证内存可见性,但是不能保证原子性
什么时候用volatile:如果写入变量值不依赖变量当前值,那么就可以用 volatile
volatile 和 synchronized 的区别?
volatile
本质是在告诉 JVM 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取。synchronized
则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。volatile
仅能使用在变量级别。synchronized
则可以使用在变量、方法、和类级别的。volatile
仅能实现变量的修改可见性,不能保证原子性。而synchronized
则可以保证变量的修改可见性和原子性。volatile
不会造成线程的阻塞。synchronized
可能会造成线程的阻塞。volatile
标记的变量不会被编译器优化。synchronized
标记的变量可以被编译器优化。
另外,会有面试官会问
volatile
能否取代synchronized
呢?答案肯定是不能,虽然说volatile
被称之为轻量级锁,但是和synchronized
是有本质上的区别,原因就是上面的几点落。
? 什么场景下可以使用 volatile 替换 synchronized ?
- 只需要保证共享资源的可见性的时候可以使用
volatile
替代,synchronized
保证可操作的原子性一致性和可见性。 volatile
适用于新值不依赖于旧值的情形。- 1 写 N 读。
- 不与其他变量构成不变性条件时候使用
volatile
。
7.锁的分类,锁的几种状态
可重入锁(sync和lock) 可中断锁(lock,如果不想等了可以中断去做其他的事) 公平锁(ReentrantLock 尽量以请求锁的顺序来获取所) 读写锁(ReentrantReadWriteLock 可以多个线程读一个线程写)
锁一共有4种状态,级别从低到高依次是:无锁,偏向锁,轻量级锁,重量级锁。锁只能逐一升级,不能降级。重量级锁
8.sleep()与wait()区别,run和start的区别,notify和notifyall区别,锁池,等待池
sleep是thread的静态方法,wait是object的方法 sleep会让出cpu调度,但是会保留锁,时间到了之后继续执行 wait会释放锁,进入等待池等待唤醒,只有notify或notify all的时候才会重新唤醒
start是线程启动,run是执行线程体 start只能调用1次,多次调用会抛异常,而run没有限制
notify是随机唤醒唤醒一个wait线程,进入锁池,而notify all是唤醒等待池里的所有wait线程
9.java中线程通信机制
同步(sync) while轮询方式(比较耗费资源) wait/notify方式
10.为什么java使用线程池
当我们需要的并发执行线程数量很多时,且每个线程执行很短的时间就结束了,这样,我们频繁的创建、销毁线程就大大降低了工作效率(创建和销毁线程需要时间、资源)。 java中的线程池可以达到这样的效果:一个线程执行完任务之后,继续去执行下一个任务,不被销毁,这样线程利用率提高了。。
11.Java中的线程池参数,共有几种
转载自:https://juejin.cn/post/7035599110807748638