synchronized实现同步的基础:Java中的每一个对象都可以作为锁,3中形式

  • 对于普通同步方法,锁时当前实例对象
  • 对于静态同步方法,锁是当前类的Class对象
  • 对于同步方法块,锁是Synchronized括号里配置的对象

    1、公平锁与非公平锁

  • private Lock lock=new ReentrantLock();//无参构造,默认为false,非公平锁

相当于private Lock lock=new ReentrantLock(false)

  • private Lock lock=new ReentrantLock(true);//有参构造,值为true,公平锁

非公平锁:饿死线程,但是效率相对较高
公平锁:阳光普照,效率相对较低

2、可重入锁

三层用的是同一把锁,所以三层的代码都可被执行。
image.png

2.1、Synchronized实现可重入锁

代码演示:由于最外层,中层和内层用的是同一把锁,所以代码均会被执行。
输出结果:

  • 最外层
  • 中层
  • 内存

    1. public class Demo {
    2. public static void main(String[] args) {
    3. Demo demo = new Demo();
    4. new Thread(()->{
    5. synchronized (demo){
    6. System.out.println("最外层");
    7. synchronized (demo){
    8. System.out.println("中层");
    9. synchronized (demo){
    10. System.out.println("内层");
    11. }
    12. }
    13. }
    14. }).start();
    15. }
    16. }

    由于同步方法上的锁为当前实例对象,所以会不断递归调用,直至栈溢出

    1. public class Demo {
    2. public synchronized void add(){
    3. add();
    4. }
    5. public static void main(String[] args) {
    6. Demo demo = new Demo();
    7. new Thread(()->{
    8. demo.add;
    9. }).start();
    10. }
    11. }

    2.2、Lock实现可重入锁

    注意:上锁与解锁缺一不可,否则其他线程在获取锁的时候,得不到锁会出现死锁的情况。 ```java public class Demo { public static void main(String[] args) {

    1. Lock lock=new ReentrantLock();
    2. new Thread(()->{
    3. try{
    4. lock.lock();
    5. System.out.println(Thread.currentThread().getName()+"最外层");
    6. try {
    7. lock.lock();
    8. System.out.println(Thread.currentThread().getName()+"内层");
    9. }finally {
    10. lock.unlock();
    11. }
    12. }finally {
    13. lock.unlock();
    14. }
    15. },"t1").start();

    } }

  1. <a name="NOw0W"></a>
  2. ## 3、死锁
  3. - 什么是死锁?
  4. 两个或者两个以上的进程在执行过程中,因为争夺资源而造成一种互相等待的现象,如果没有外力干涉,他们无法再执行下去。
  5. - 产生死锁的原因
  6. -系统资源不足<br />-进程运行推进顺序不合适<br />-资源分配不当
  7. - 死锁演示-为了增减概率sleep
  8. ```java
  9. public class DeadLockDemo {
  10. static Object a = new Object();
  11. static Object b = new Object();
  12. public static void main(String[] args) {
  13. new Thread(() -> {
  14. synchronized (a) {
  15. System.out.println(Thread.currentThread().getName() + "拥有锁a,等待获取锁b");
  16. try {
  17. TimeUnit.SECONDS.sleep(1);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. synchronized (b) {
  22. System.out.println(Thread.currentThread().getName() + "拥有锁b,等待获取锁a");
  23. }
  24. }
  25. },"A").start();
  26. new Thread(() -> {
  27. synchronized (b) {
  28. System.out.println(Thread.currentThread().getName() + "拥有锁b,等待获取锁a");
  29. try {
  30. TimeUnit.SECONDS.sleep(1);
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }
  34. synchronized (a) {
  35. System.out.println(Thread.currentThread().getName() + "拥有锁a,等待获取锁b");
  36. }
  37. }
  38. },"B").start();
  39. }
  40. }
  • 验证死锁

1、jps 类似于Linux ps -ef,在jdk的bin安装目录下,环境变量必须配置
2、jstack jvm自带的堆栈跟踪工具

1、演示
第一步 jps -l
第二步 jstack 端口号 此时便会提示是否有死锁