给我一首歌的时间,带你了解线程安全和死锁(3)

举报
bug郭 发表于 2022/09/30 22:56:54 2022/09/30
【摘要】 大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流作者简介:CSDN java领域新星创作者blog.csdn.net/bug…掘金LV3用户 juejin.cn/user/bug…阿里云社区专家博主,星级博主,developer.a...

大家好,我是bug郭,一名双非科班的在校大学生。对C/JAVA、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:

造成死锁的必要条件

  • 互斥使用: 当一个锁被线程占用时,其他线程就不能占用该锁了(锁的本质,原子性)
  • 不可抢占: 当一个锁被线程占用后,其他线程不能把该锁抢走(也就好比人家已经有对象,你就不能挖别人墙角)
  • 请求和保持: 当一个线程占用多把锁后,如果不释放锁,那么这些锁始终被该线程所有!
  • 环路等待: 就入哲学家就餐,同时拿筷子,造成了环路等待,a等b,b等c,c又等a!
    避免环路等待,需要约定加锁顺序,然后线程都按照该顺序加锁!

synchronizedvolatile区别

我们再来总结一下volatile的作用!
volatile关键字,可以保证该变量内存可见性,避免编译器偷懒优化,直接在寄存器中读取数据,导致线程不安全!

synchronized:

  • 给对象加锁,当多个线程对同一个变量更改时,保证线程安全

  • 给变量加锁,保证指令原子性

  • 保证内存可见性

  • 避免指令重排序

可以看到synchronized关键字,可以解决所有的线程不安全问题!
那我们是不是无脑用synchronized就好了
但是我我们知道synchronized加锁后,代码的执行效率就大打折扣!发挥不了多线程并发编程的优势!使用时需要视情况而定!!!

volatile只是保证了该变量内存可见性!并不能避免其他线程安全问题!
synchronized加锁后,会造成线程阻塞,volatile
并不会导致阻塞!!!

wait 和notify方法

等待和通知线程

这两个方法是Object类中的方法!

我们知道线程的调度是随机的,抢占性!而java下的waitnotify方法可以保证线程的执行顺序!
我们来学习一下这两个方法的使用!
调用wait方法后线程就会阻塞,直到有线程调用了notify通知!

public class Thread_20 {
    public static void main(String[] args) {
        Thread t1 = new Thread(()->{
           Object object = new Object();
            System.out.println("wait前:");
            try {
                object.wait();//阻塞
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("wait后:");
        });
        t1.start();
        t1.getState();
    }
}

在这里插入图片描述
本来预期是线程阻塞结果却抛出非法的监听器状态异常!

我们来看看wait方法的作用

  • 释放锁
  • 阻塞状态,等待其他线程通知
  • 收到通知,重新获取锁,继续往下执行

而我们上述代码连锁都没有又如何释放锁呢!

所以waitnotify方法需要搭配synchronized关键字使用!
正确用法:

    public class Thread_21 {
        private static Object object = new Object();
        public static void main(String[] args) throws InterruptedException {
            Thread t1 = new Thread(()->{
                //进行wait操作
                System.out.println("wait前");
                synchronized (object){
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("wait后");
            });
            t1.start();
            t1.sleep(3000);
            Thread t2 = new Thread(()->{
                System.out.println("notify前");
                synchronized(object){
                   object.notify();
                }
                System.out.println("notify后");
            });
            t2.start();
        }
    }

在这里插入图片描述
我们可以看到,当object执行了wait方法后就造成了线程阻塞,直到执行notify通知后,线程才拿到锁继续执行下去!

notifynotifyAll区别

当我们多个线程都对object加锁后,notify通知后,只会随机给一个线程进行通知,然后该线程就可以拿到锁,执行线程!

notifyAll方法是通知所有阻塞线程,此时就会产生锁竞争!

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。