1.初步认识synchronized
先来看下利用 synchronized 实现 同步的基 础 : Java 中的每一个 对 象都可以作 为锁 。具体表 现为 以下 3 种形式。 :对于普通同步方法, 锁 是当前 实 例 对 象。对于静 态 同步方法, 锁 是当前 类 的 Class 对 象。对于同步方法 块 , 锁 是 Synchonized 括号里配置的 对 象。当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。区别:当锁为Class对象时 ,同时被static修饰和synchronized修饰都不能被其他线程锁住调用,但是它们可以执行该类的synchronized修饰普通方法和没有synchronized修饰的方法当锁为实例对象时 ,只能锁住该实例修饰普通方法,对于其他实例的任何方法与当前实例( 除synchronized修饰的普通方法外 )都不起作用当锁同步方法块时, 括号里面是什么就对应锁住什么
2 JAVA的请求头
synchronized用的 锁 是存在 Java 对 象 头 里的。如果 对 象是数 组类 型, 则 虚 拟 机用 3 个字 宽 (Word )存 储对 象 头 ,如果 对 象是非数 组类 型, 则 用 2 字 宽 存 储对 象 头 。在 32 位虚 拟 机中, 1 字 宽 等于4 字 节 ,即 32bit ,如图 所示。
Java对象 头 里的 Mark Word 里默 认 存 储对 象的 HashCode 、分代年 龄 和 锁标记 位。 32 位 JVM 的Mark Word 的默 认 存 储结构如图 所示。
在运行期间, Mark Word 里存 储 的数据会随着 锁标 志位的 变 化而 变 化。 Mark Word 可能 变 化为 存 储 以下 4种数据,如图 所示。
在64 位虚 拟 机下, Mark Word 是 64bit 大小的,其存 储结 构如表 2-5 所示
3.死锁
什么是死锁:
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。死锁是并发系统中的一种重要现象,它可能导致系统资源的浪费和进程的停滞。
例如:
下面代码 t1 拿到 锁 之后,因 为 一些异常情况没有 释 放 锁 (死循环 )。又或者是 t1 拿到一个数据 库锁 , 释 放 锁 的 时 候抛出了异常,没 释 放掉。public class DeadLockDemo { privat static String A = "A"; private static String B = "B"; public static void main(String[] args) { new DeadLockDemo().deadLock(); } private void deadLock() { Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized (A) { try { Thread.currentThread().sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (B) { System.out.println("1"); } } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { synchronized (B) { synchronized (A) { System.out.println("2"); } } } }); t1.start(); t2.start(); } }
死锁产生的四个条件
1.互斥条件:指同一资源不能被多个线程访问
2.持有并等待条件:指当前线程已经持有一个资源,又去申请另外一个,但此时另外的这个资源被别人已经占用了,当前线程只能处于等待状态
3. 不可剥夺条件:当当前线程已经持有了某个资源,只有自己使用完才能将资源释放
4.环形等待条件:当前的几个线程都占用了不同的资源,但是又需要别的线程占用的资源才能使用完并释放锁
解决死锁的四种方式
1. 破坏互斥条件:能允许同一资源被多线程访问
2. 破坏持有并等待条件:保证当前线程执行时能获取到所有资源,否则不可以执行继续等待
3. 破坏不可剥夺条件:当某个线程一直占用某个资源时,强制剥夺他的资源给别的线程
4. 破坏环形等待条件:对待需要资源排序,要求每个线程按照顺序获取资源