1.考查是否知道并发编程三要素
并发编程三要素是否知道,能否分别解释下,举个简单的例子
原子性
public class XdTest {
private int num = 0;
//使用lock,每个对象都是有锁,只有获得这个锁才可以进行对应的操作
Lock lock = new ReentrantLock();
public void add1(){
lock.lock();
try {
num++;
}finally {
lock.unlock();
}
}
//使用synchronized,和上述是一个操作,这个是保证方法被锁住而已,上述的是代码块被锁住
public synchronized void add2(){
num++;
}
} 有序性
可见性
2.常见的进程、线程间调度算法
说下你知道的调度算法,比如进程间的调度
常见的线程间的调度算法是怎样的,java是哪种
线程调度是指系统为线程分配CPU使用权的过程,主要分两种
3.考查对常见的锁是否掌握
你日常开发里面用过java里面有哪些锁?分别解释下
小结:悲观锁适合写操作多的场景,乐观锁适合读操作多的场景,乐观锁的吞吐量会比悲观锁多
小结:非公平锁性能高于公平锁,更能重复利用CPU的时间
小结:可重入锁能一定程度的避免死锁 synchronized、ReentrantLock 重入锁
private void meathA(){
//获取锁 TODO
meathB();
}
private void meathB(){
//获取锁 TODO
//其他操作
} 小结:不会发生线程状态的切换,一直处于用户态,减少了线程上下文切换的消耗,缺点是循环会消耗CPU
常见的自旋锁:TicketLock,CLHLock,MSCLock
下面三种是Jvm为了提高锁的获取与释放效率而做的优化 针对Synchronized的锁升级,锁的状态是通过对象监视器在对象头中的字段来表明,是不可逆的过程
还有一些其他的锁:分段锁、行锁、表锁
4.考查对常见的死锁是否掌握
上机实战:写个多线程死锁的例子
public class DeadLockDemo {
private static String locka = "locka";
private static String lockb = "lockb";
public void methodA(){
synchronized (locka){
System.out.println("我是A方法中获得了锁A"+Thread.currentThread().getName());
//让出CPU执行权,不释放锁
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockb){
System.out.println("我是A方法中获得了锁B"+Thread.currentThread().getName());
}
}
}
public void methodB(){
synchronized (lockb){
System.out.println("我是A方法中获得了锁B"+Thread.currentThread().getName());
//让出CPU执行权,不释放锁
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (locka){
System.out.println("我是B方法中获得了锁A"+Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
System.out.println("主线程运行开始:"+Thread.currentThread().getName());
DeadLockDemo deadLockDemo = new DeadLockDemo();
new Thread(()->{
deadLockDemo.methodA();
}).start();
new Thread(()->{
deadLockDemo.methodB();
}).start();
System.out.println("主线程运行结束:"+Thread.currentThread().getName());
}
}
控制台输出
主线程运行开始:main
我是A方法中获得了锁AThread-0
主线程运行结束:main
我是A方法中获得了锁BThread-1
注意:这里看到控制台已经输出了内容,但是程序并没有结束,就一直卡在这里了!
那上面的例子怎么解决死锁,优化下代码
/**
* 解决死锁,通过调整锁的范围
*/
public class DeadLockDemo {
private static String locka = "locka";
private static String lockb = "lockb";
public void methodA(){
synchronized (locka){
System.out.println("我是A方法中获得了锁A"+Thread.currentThread().getName());
//让出CPU执行权,不释放锁
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (lockb){
System.out.println("我是A方法中获得了锁B"+Thread.currentThread().getName());
}
}
public void methodB(){
synchronized (lockb){
System.out.println("我是A方法中获得了锁B"+Thread.currentThread().getName());
//让出CPU执行权,不释放锁
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (locka){
System.out.println("我是B方法中获得了锁A"+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
System.out.println("主线程运行开始:"+Thread.currentThread().getName());
DeadLockDemo deadLockDemo = new DeadLockDemo();
new Thread(()->{
deadLockDemo.methodA();
}).start();
new Thread(()->{
deadLockDemo.methodB();
}).start();
System.out.println("主线程运行结束:"+Thread.currentThread().getName());
}
}
控制台输出
主线程运行开始:main
我是A方法中获得了锁AThread-0
主线程运行结束:main
我是A方法中获得了锁BThread-1
我是A方法中获得了锁BThread-0
我是B方法中获得了锁AThread-1
5.考查对常见的不可重入锁是否掌握
上机实战:设计一个简单的不可重入锁
/**
* 不可重入锁
*
* 不可重入锁:若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞
*/
public class UnreentrantLock {
private boolean isLocked = false;
public synchronized void lock(){
System.out.println("进入lock加锁"+Thread.currentThread().getName());
//判断是否已经被锁,如果被锁则当前请求的线程进行等待
while (isLocked){
System.out.println("进入wart等待"+Thread.currentThread().getName());
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有被锁,进行加锁
isLocked = true;
}
public synchronized void unlock(){
System.out.println("进入unlock解锁"+Thread.currentThread().getName());
isLocked = false;
//唤醒对象锁池里面的一个线程
notify();
}
}
public class Main {
private UnreentrantLock unreentrantLock = new UnreentrantLock();
//加锁建议在try里面,解锁建议在finally
public void methodA(){
try {
unreentrantLock.lock();
System.out.println("methodA方法被调用");
methodB();
} finally {
unreentrantLock.unlock();
}
}
public void methodB(){
try {
unreentrantLock.lock();
System.out.println("methodB方法被调用");
} finally {
unreentrantLock.unlock();
}
}
public static void main(String [] args){
//演示的是同个线程
new Main().methodA();
}
}
控制台输出
进入lock加锁main
methodA方法被调用
进入lock加锁main
进入wart等待main
6.考查对常见的重入锁是否掌握
上机实战:设计一个简单的可重入锁
/**
* 可重入锁
* <p>
* 可重入锁:也叫递归锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁
*/
public class ReentrantLock {
private boolean isLocked = false;
//用于记录是不是重入的线程
private Thread lockedOwner = null;
//累计加锁次数,加锁一次累计加一,解锁一次减少1
private int lockedCount = 0;
public synchronized void lock() throws InterruptedException {
System.out.println("进入lock加锁" + Thread.currentThread().getName());
Thread thread = Thread.currentThread();
//判断是否是同个线程获取锁,引用地址的比较
while (isLocked && lockedOwner != thread) {
System.out.println("进入wart等待" + Thread.currentThread().getName());
System.out.println("当前锁状态 isLocked = " + isLocked);
System.out.println("当前count数量 lockedCount = " + lockedCount);
wait();
}
//如果没有被锁,进行加锁
isLocked = true;
lockedOwner = thread;
lockedCount++;
}
public synchronized void unlock() {
System.out.println("进入unlock解锁" + Thread.currentThread().getName());
Thread thread = Thread.currentThread();
//线程A加的锁,只能由线程A解锁,其他线程B不能解锁
if (thread==this.lockedOwner){
lockedCount--;
if (lockedCount==0){
isLocked = false;
lockedOwner = null;
//唤醒对象锁池里面的一个线程
notify();
}
}
}
}
public class Main {
private ReentrantLock reentrantLock = new ReentrantLock();
//加锁建议在try里面,解锁建议在finally
public void methodA(){
try {
reentrantLock.lock();
System.out.println("methodA方法被调用");
methodB();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
public void methodB(){
try {
reentrantLock.lock();
System.out.println("methodB方法被调用");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
reentrantLock.unlock();
}
}
public static void main(String [] args){
//演示的是同个线程
new Main().methodA();
}
}
控制台输出
进入lock加锁main
methodA方法被调用
进入lock加锁main
methodB方法被调用
进入unlock解锁main
进入unlock解锁main
7.考查对常见的synchronized是否掌握,新版JDK6里面优化了什么
对synchronized了解不,能否介绍下你对synchronized的理解
jdk1.6后进行了优化,你知道哪些大的变化
8.考查对常见的CAS是否掌握
了解CAS不,能否解释下什么是CAS
9.并发编程面试核心点CAS常见存在的问题考查
CAS会存在什么比较严重的问题?
能否解释下什么是ABA问题,怎么避免这个问题呢?
本文作者为DBC,转载请注明。


