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,转载请注明。