JavaThread 09 守护(daemon)线程&&线程同步机制的理解

4.2 守护(daemon)线程


  • 线程分为 用户线程守护线程
  • JVM 虚拟机 必须 确保用户线程执行完毕
  • JVM 不用等待 守护 线程执行完毕 < 守护线程跟 主线程和用户线程 不是一路子的。 >
  • 如:后台记录操作日志,监控内存,垃圾回收等等。都是守护线程!

什么叫做 JVM 虚拟机 不等待 守护线程??


答:就是说 守护线程的 关闭和停止,不是 由 JVM 虚拟机决定的。而是 由 系统决定的。当程序真正的被停止后。或者说 当所有的用户线程和主线程 停止后。 守护线程 才会被 系统关闭和停止,而并非 JVM 虚拟机。JVM 虚拟机 只会 关闭和停止 用户线程,当用户线程执行的事务 完毕后(代码执行完了后),JVM 就会 帮这些用户线程 进行 自动的关闭 和停止!而 守护线程 是 看看 整个程序 是否还存在 用户线程 或 主线程 是否还有存在的意义。而决定 自己到底 是否还要 继续守护下去。

我们可以说,守护线程 是 后台线程,它的优先级 较低!整个程序 都不需要等待这个 线程 执行完成。这样 做的 意义就是 当子线程无限循环时,出现退不出程序的情况。也就是避免 孤儿线程。此时 你把 这个 线程 设定为 守护线程即可。切记 一些 需要进行 一直 死循环 监视的 线程,尽量 设为 守护线程!!!

package www.muquanyu.lesson03;

public class DaemonDemo {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread A = new Thread(god);
        Thread B = new Thread(you);
        A.setDaemon(true);
        A.start();
        B.start();
        while(A.getState() != Thread.State.TERMINATED)
        {
            System.out.println("上帝--->"+A.getState());
        }
        System.out.println("上帝--->"+A.getState());
    }
}
//上帝(守护线程)
class God implements Runnable{
    @Override
    public void run() {
        System.out.println("上帝保佑着你!上帝不会死的!");
    }
}


//你(子线程)
class You implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<100;++i)
        {
            System.out.println("你一生都开心的活着");
        }
        System.out.println("-====goodbye! world!====-");
    }
}

你会发现 God 上帝 只有短短的一行代码,但是 它这个 线程 好像一直没有消失!!!而是 等到 所有的线程甚至是 进程消失后,它才结束了自己的一生!
在这里插入图片描述

这样子写还不够明显,我们可以换一种方式,让上帝处理的代码变成 一个死循环!

package www.muquanyu.lesson03;

public class DaemonDemo {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();
        Thread A = new Thread(god);
        Thread B = new Thread(you);
        A.setDaemon(true);
        A.start();
        B.start();
    }
}
//上帝(守护线程)
class God implements Runnable{
    @Override
    public void run() {
        while (true)
        {
            System.out.println("上帝保佑着你!上帝不会死的!");
        }
    }
}


//你(子线程)
class You implements Runnable{
    @Override
    public void run() {
        for(int i = 0;i<100;++i)
        {
            System.out.println("你一生都开心的活着");
        }
        System.out.println("-====goodbye! world!====-");
    }
}

在这里插入图片描述


4.3 线程同步机制

4.3.1 并发问题

  • 并发:同一个对象多个线程 同时操作!
    在这里插入图片描述
    在这里插入图片描述

所谓并发问题,就是 多个对象没有规则的去 操作同一个资源!这会导致 出现 资源乱抢 情况,场面一度混乱。你会发现 有的人 抢到的 资源 甚至 都不是 他需要的资源(资源分配错误),还可能会出现 多个对象 都说 那个资源是它们的!(资源分配重复)。

上述出现的情况是错误的,资源一共就那么点儿,所以不可能出现 重复的现象。也更不可能 出现 资源不对的情况!否则就属于 错误现象!

能解决 并发问题的方法 就是 线程同步


4.3.2 线程同步

  • 现实生活中,我们会遇到 “同一个资源,多个人都想使用” 的问题,比如说 食堂排队在打饭,每个人都想要吃饭,但是必须遵守基本的道德准则和规范规则!! 否则你一闹事 可能会导致 大家 都吃不到饭了。

  • 处理多线程问题的时候,多个线程访问同一个对象,并且某些线程还想去修改这个对象。这时候我们就需要线程同步。线程同步其实就是一种等待机制。 多个需要同时访问此对象的线程需要进入 这个 对象 的 “等待池” 形成队列,等待前面的线程使用完毕,下一个线程再去使用!(这样就有规则和规范,并且 效率也不会因此降低多少!!!

那么 后面排队的人,也就是在 等待池里面的人,怎么会知道 前面的那个线程 正在 处理资源呢?这就涉及到 锁的 概念了!


4.3.3 队列和锁

在这里插入图片描述
前面三个同学,居然 并排 ?? 这不就是 典型的 线程并发问题吗?这是 错误的,不正确的,是不可取的。

  • 队列必须伴随着锁

为什么呢?


答:比如说 你们排队上厕所,你进入一个 厕房,发现自己 没锁门,那肯定 会有人 拽一下门,看看到底锁没锁。如果有性质恶劣的人,甚至 会想着 把你 撵出来,他用这个 厕房!!!这就不对劲了。所以 队列 肯定 会伴随着 锁!

在讲 sleep 的时候,我们提到过,每个对象 都自带了一把锁,为了防止 自己进入队列后,没有 锁 对自己进行保护措施。而sleep 是无法 释放 掉 锁的!

这里的每个对象,指的并不是 线程!线程是被锁住的那个对象。比如 你上厕所,锁在哪里呢?肯定是厕房的锁呀!厕房的锁是提供给你用的,是把你锁在厕房里的!(此时厕房 属于 “同步监视器”


4.3.3 synchronized 同步

  • 由于统一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入 “锁机制” ,而当你使用 synchronized 同步的时候,就必须要提供一个对象来作为 “同步监视器”,审查每一个想使用它的线程对象,当一个 线程获得该对象的 的锁(排它锁)后,就会独占资源,其它线程必须等待该线程使用释放锁后(代码执行完就自动使用释放锁了),其他的线程才能继续进行对其资源的处理。

  • 这可能会引起一些问题(降低性能的问题):

  1. 一个线程被 对象锁住后,会导致其它线程 挂起!

  2. 在多个线程竞争下,加锁和释放锁,会导致比较 频繁的切换 和 调度延时,这会 引起 性能问题。

  3. 如果一个 优先级高的线程 去等待一个 优先级 低的线程 去释放锁,那么这就演化成了 优先级的 倒置问题!是性能的 大问题。

这就说明了 “鱼和熊掌” 二者不能兼得 的道理。你想要性能 那么数据在大概率情况下,是避免不了危险的。你想要安全,那么性能在大概率情况下也是避免不了变慢的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值