JUC:6、多线程锁

6.1 锁的八种情况

1、两个同步方法,一个对象,两个线程,分别调用 getOne()和 getTwo(), 打印? //1 2

2、在 getOne() 方法中添加睡眠3秒,打印? //1 2

3、添加非同步方法,启动三个线程,打印? // 3 1 2

4、创建两个对象,一个调用 getOne() 一个调用getTwo(), 打印? //2 1

5、将 getOne() 修改为静态同步方法,一个对象,打印? //2 1

6、将 getTwo() 修改为静态同步方法,一个对象,打印? //1 2

7、将 getTwo() 修改为非静态同步方法,两个对象, 打印? //2 1

8、两个静态同步方法,两个对象,打印?// 1 2

总结:

  • 对于普通同步方法:锁的是当前对象
  • 对于静态同步方法:锁的是类
  • 对象锁和类锁不是同一把锁
  • 对于同步方法块:锁的是synchronized括号里配置的对象

6.2 公平锁和非公平锁

非公平锁:

是指多个线程获取锁的顺序,并不是按照申请锁的顺序,有可能申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转,或者饥饿的线程(也就是某个线程一直得不到锁)

效率高,但是会造成线程饿死

公平锁:

是指多个线程按照申请锁的顺序来获取锁,类似于排队买饭,先来后到,先来先服务,就是公平的,也就是队列

private final ReentrantLock lock = new ReentrantLock(true);

6.3 可重入锁(递归锁)

什么是 “可重入”,可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。

synchronizedReentrantLock都是可重入锁。

synchronized是隐式的可重入锁,ReentrantLock是显式的可重入锁。

synchronized代码示例:

public static void main(String[] args) {
    //synchronized
    Object o = new Object();
    new Thread(()->{
        synchronized(o) {
            System.out.println(Thread.currentThread().getName() + " 外层");

            synchronized(o) {
                System.out.println(Thread.currentThread().getName() + " 中层");

                synchronized(o) {
                    System.out.println(Thread.currentThread().getName() + " 内层");
                }
            }
        }
    }, "t1").start();
}

ReentrantLock代码示例:

public static void main(String[] args) {
	//lock
	Lock lock = new ReentrantLock();
	
	new Thread(()->{
	    try{
	      lock.lock();
	      System.out.println(Thread.currentThread().getName() + "外层");
	
	      try {
	          lock.lock();
	          System.out.println(Thread.currentThread().getName() + "中层");
	
	          try {
	              lock.lock();
	              System.out.println(Thread.currentThread().getName() + "内层");
	          } finally {
	              lock.unlock();
	          }
	
	      } finally {
	          lock.unlock();
	      }
	
	    } finally {
	        lock.unlock();
	    }
	}, "t1").start();
 }

注意:有几个lock()就需要有几个unlock(),否则其他线程会拿不到锁。

6.4 死锁

1、什么是死锁?

两个或两个以上的进程,因为资源争夺的问题,而造成互相等待的现象。如果没有外力干涉,这些线程都不会继续执行下去。

2、产生死锁的原因:

  • 系统资源不足
  • 资源分配不当
  • 进程推进顺序不合理

3、死锁实例:

package lock;

public class DeadLock {

    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();

        new Thread(()->{
            synchronized (a) {
                System.out.println(Thread.currentThread().getName() + "获取了锁a,想要获取锁b");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (b) {
                    System.out.println(Thread.currentThread().getName() + "获取了锁b");
                }
            }
        }, "A").start();

        new Thread(()->{
            synchronized (b) {
                System.out.println(Thread.currentThread().getName() + "获取了锁b,想要获取锁a");

                synchronized (a) {
                    System.out.println(Thread.currentThread().getName() + "获取了锁a");
                }
            }
        }, "B").start();
    }
}

如何查看死锁:
1、terminal中输入jsp -l(这个命令在jdk的bin目录中),查看java的进程号
2、jstack [进程号],往下翻,可以找到以下信息:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值