Java中的锁一般指内置锁,也称互斥锁。
多个线程对共享资源进行访问时,只有一个线程可以获取到该共享资源的锁,当线程B获取到锁,线程A尝试访问时,线程A必须等待或阻塞,直到线程B释放该锁。一个Synchronized块包含两部分:锁以及这个锁保护的代码块。执行线程进入Synchronized块之前会自动获得锁,获得锁的唯一途径是进入这个内部锁保护的同步块或方法,正常退出或执行过程中抛出异常时线程会放弃对Synchronized块的控制并释放锁。
每个java对象都可以作为一个实现同步的锁,锁只能是引用类型。根据使用方式的不同我们将锁分为对象锁和类锁,对象锁作用在实例方法或实例对象上,类锁作用在静态方法或Class对象上。一个类可以有多个实例对象,所以一个类的对象锁可能会有多个,但是每个类只有一个Class对象,所以类锁只有一个。
死锁:多个并发进程因争夺系统资源而发生互相等待的现象。造成此种现象的主要是因为系统资源有限以及进程推进顺序不合理。
死锁产生的4个必要条件:
1.互斥:资源一次只能被一个线程访问;
2.占有且等待:一个线程已经占有资源(一个或多个),同时还有资源未被满足,正在等待其他线程释放;
3.不可抢占:资源一旦被其他线程占用,不能将此资源抢过来;
4.循环等待:每一个线程占有另一个线程所需的至少一种资源;
避免死锁方法举例:
1.破坏占有且等待:所有线程在运行之前,一次性占用运行过程中全部所需资源
优点:简单且安全
缺点:造成资源浪费,缺少某项资源则无法启动,另外,已经占用的资源也无法被使用;发生饥饿现象
改良:只占用运行初期需要的资源,执行过程中逐步释放使用完毕的资源并占用新资源
2.破坏不可抢占:已经占有资源的无法占有其他资源时,释放已经占有的资源,等到有需要再重新申请
死锁举例
/**
* @className DeadLock
* @description 死锁举例
* @author BSmile
* @date 2018年3月18日 下午10:52:04
*/
public class DeadLock {
/** 对象锁1 */
public static String objLock1 = "objLock1";
/** 对象锁2 */
public static String objLock2 = "objLock2";
public static void main(String[] args) {
//同时启动两个并发线程,Lock1先获取对象锁1,Lock2获取对象锁2,
//然后让Lock1去获取对象锁2,Lock2获取对象锁1,
//因为都没有释放锁,所以同时都获取不到,所以造成死锁
new Thread(new Lock1()).start();
new Thread(new Lock2()).start();
}
}
/**
* @className Lock1
* @description Lock1先获取对象锁1,再去获取对象锁2,发现对象锁2被Lock2占用了
* @author BSmile
* @date 2018年3月18日 下午11:00:29
*/
public class Lock1 implements Runnable {
@Override
public void run() {
System.out.println("Lock1 running");
synchronized (DeadLock.objLock1) {
System.out.println("Lock1 get objLock1");
try {
//Lock1获取到对象锁1等待3秒,让Lock2获取对象锁2
Thread.sleep(3*1000);
synchronized (DeadLock.objLock2) {
System.out.println("Lock1 get objLock2");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* @className Lock2
* @description Lock2先获取对象锁2,再去获取对象锁1,发现对象锁1被Lock1占用了
* @author BSmile
* @date 2018年3月18日 下午11:30:26
*/
public class Lock2 implements Runnable {
@Override
public void run() {
System.out.println("Lock2 running");
synchronized (DeadLock.objLock2) {
System.out.println("Lock2 get objLock2");
try {
//Lock2获取到对象锁2等待3秒,让Lock1获取对象锁1
Thread.sleep(3*1000);
synchronized (DeadLock.objLock1) {
System.out.println("Lock2 get objLock1");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行结果如下:
Lock1 running
Lock1 get objLock1
Lock2 running
Lock2 get objLock2