- 悲观锁:认为资源非常紧张,遇到共享中的资源直接挂起线程,等待唤醒。例如synchronized
- 乐观锁:认为资源很可能不紧张,遇到共享资源直接执行操作,如果结果与预期不一致则再次尝试,循环直到成功。例如CAS
悲观锁遇到资源不紧张时,挂起唤醒线程相对来说资源消耗过大;乐观锁遇到资源紧张时执行一直无法成功,cpu自旋,消耗过大。
- 公平锁指的是锁释放时,排队中的线程先lock的先获得锁。
- 非公平锁指的是锁释放时,排队中的线程随机取一个获得锁。
- 一个线程获得读锁,其他线程也可以获得读锁,但不能获得写锁。
- 一个线程获得写锁,其他线程既不能读也不能写。
竞态条件
多个线程操作共享对象时,由于操作顺序的原因可能导致预期之外的结果,称为竞态条件。
存在竞态条件的代码段称为临界区。
解除方法是加锁(synchronized或者lock)
加锁方式
//synchronized方式
synchronized(String.class){
System.out.println("b");
}
synchronized(ob){
System.out.println("b");
}
public synchronized void getSyn(){}
//Lock方式
Lock lock=new ReentrantLock();
lock.lock();
lock.unlock();
lock.lockInterruptibly();//此方法类似于lock(),但是可以响应interrupt()抛出异常
lock.unlock();
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
rwLock.readLock().lock();
rwLock.readLock().unlock();
rwLock.writeLock().lock();
rwLock.writeLock().unlock();
synchronized和Lock的异同
相同点: synchronized、ReentrantLock都是独占锁,默认都是非公平锁(解锁后随机分配新锁)
不同点:
- synchronized是在虚拟机层面实现(字节码中代码块上下被monitorenter、monitorexit包围,只有一个线程能访问),Lock是通过类实现
- synchronized自动释放,Lock都需要手动释放unlock();
- ReentrantLock还可以实现公平锁(new ReentrantLock(true););ReentrantLock还可以实现tryLock();ReentrantReadWriteLock还可以实现读写锁;
死锁示例
static void deadLockTest(){
new Thread(new Runnable() {
@Override
public void run() {
synchronized(String.class){
Math.random(); //拖延时间,更容易进入死锁状态
synchronized(int.class){
System.out.println("a");
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized(int.class){
synchronized(String.class){
System.out.println("b");
}
}
}
}).start();
}
停止线程
- t.stop()
- t.interrupt()
注意interrupt()本身不会直接终止线程,有两种情况:
- 线程正在正常运行,此时interrupt()只是将线程标记为interrupted状态,可以用while (!Thread.currentThread().isInterrupted()){}来捕获状态终止循环,借此终止线程。
- 线程正在sleep()/wait()/join()状态,此时interrupt()将在子线程中抛出一个InterruptedException,可以用try catch捕获错误终止线程。