多线程与并发编程【守护线程、线程同步】(三)-全面详解(学习总结---从入门到深化)

news2024/11/16 17:57:15

 

 

目录

守护线程

 什么是守护线程

 守护线程的使用

线程同步

实现线程同步

线程同步的使用


守护线程

 什么是守护线程

  在Java中有两类线程:

        User Thread(用户线程):就是应用程序里的自定义线程。

        Daemon Thread(守护线程):比如垃圾回收线程,就是最典型的守护线程。

 守护线程(即Daemon Thread),是一个服务线程,准确地来说 就是服务其他的线程,这是它的作用,而其他的线程只有一种,那 就是用户线程。

 守护线程特点

      守护线程会随着用户线程死亡而死亡。

守护线程与用户线程的区别

用户线程,不随着主线程的死亡而死亡。用户线程只有两种情况会 死掉,1在run中异常终止。2正常把run执行完毕,线程死亡。

守护线程,随着用户线程的死亡而死亡,当用户线程死亡守护线程 也会随之死亡。

 守护线程的使用

/**
* 守护线程类
*/
class Daemon implements  Runnable{
    @Override
    public void run() {
        for(int i=0;i<20;i++){
              System.out.println(Thread.currentThread().getName()+" "+i);
            try {
                Thread.sleep(2000);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
   }
}
class UsersThread implements Runnable{
    @Override
    public void run() {
        Thread t = new Thread(new Daemon(),"Daemon");
        //将该线程设置为守护线程
        t.setDaemon(true);
        t.start();
        for(int i=0;i<5;i++){
          System.out.println(Thread.currentThread().getName()+" "+i);
            try {
                Thread.sleep(500);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
   }
}
public class DaemonThread {
    public static void main(String[] args)throws Exception {
        Thread t = new Thread(new UsersThread(),"UsersThread");
        t.start();
        Thread.sleep(1000);
        System.out.println("主线程结束");
   }
}

线程同步

什么是线程同步

线程冲突现象

 同步问题的提出

现实生活中,我们会遇到“同一个资源,多个人都想使用”的问题。 比如:教室里,只有一台电脑,多个人都想使用。天然的解决办法 就是,在电脑旁边,大家排队。前一人使用完后,后一人再使用。

 线程同步的概念

处理多线程问题时,多个线程访问同一个对象,并且某些线程还想 修改这个对象。 这时候,我们就需要用到“线程同步”。 线程同步其 实就是一种等待机制,多个需要同时访问此对象的线程进入这个对 象的等待池形成队列,等待前面的线程使用完毕后,下一个线程再 使用。

线程冲突案例演示 

我们以银行取款经典案例来演示线程冲突现象。 银行取钱的基本流程基本上可以分为如下几个步骤。

(1)用户输入账户、密码,系统判断用户的账户、密码是否匹配。

(2)用户输入取款金额

(3)系统判断账户余额是否大于或等于取款金额

(4)如果余额大于或等于取款金额,则取钱成功;如果余额小于取 款金额,则取钱失败。

/**
* 账户类
*/
class Account{
    //账号
    private String accountNo;
    //账户的余额
    private double balance;
    public Account() {
   }
    public Account(String accountNo, double balance) {
        this.accountNo = accountNo;
        this.balance = balance;
   }
    public String getAccountNo() { return accountNo;
   }
    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
   }
    public double getBalance() {
        return balance;
   }
    public void setBalance(double balance) {
        this.balance = balance;
   }
}
/**
* 取款线程
*/
class DrawThread implements Runnable{
    //账户对象
    private Account account;
    //取款金额
    private double drawMoney;
    public DrawThread(Account account,double drawMoney){
        this.account = account;
        this.drawMoney = drawMoney;
   }
    /**
     * 取款线程
 */
    @Override
    public void run() {
        //判断当前账户余额是否大于或等于取款金额
        if(this.account.getBalance() >= this.drawMoney){
          System.out.println(Thread.currentThread().getName()+" 取钱成功!吐出钞
票:"+this.drawMoney);
            try {
                Thread.sleep(1000);
           } catch (InterruptedException e){
                e.printStackTrace();
           }
            //更新账户余额
          this.account.setBalance(this.account.getBalance()- this.drawMoney);
            System.out.println("\t 余额为:"+this.account.getBalance());
       }else{
          System.out.println(Thread.currentThread().getName()+" 取钱失败,余额不足");
       }
   }
}
public class TestDrawMoneyThread {
    public static void main(String[] args) {
        Account account = new Account("1234",1000);
        new Thread(new DrawThread(account,800),"老公").start();
        new Thread(new DrawThread(account,800),"老婆").start();
   }
}

实现线程同步

由于同一进程的多个线程共享同一块存储空间,在带来方便的同 时,也带来了访问冲突的问题。Java语言提供了专门机制以解决这 种冲突,有效避免了同一个数据对象被多个线程同时访问造成的这 种问题。这套机制就是synchronized关键字。

 synchronized语法结构:

synchronized(锁对象){ 
   同步代码
 }

synchronized关键字使用时需要考虑的问题:

    需要对那部分的代码在执行时具有线程互斥的能力(线程互斥:并行变串行)。

   需要对哪些线程中的代码具有互斥能力(通过synchronized锁对象来决定)。

它包括两种用法:

synchronized 方法和 synchronized 块。

 1 synchronized 方法 

    通过在方法声明中加入 synchronized关键字来声明,语法如 下:

    

public  synchronized  void accessVal(int newVal);

synchronized 在方法声明时使用:放在访问控制符(public)之前 或之后。这时同一个对象下synchronized方法在多线程中执行 时,该方法是同步的,即一次只能有一个线程进入该方法,其他 线程要想在此时调用该方法,只能排队等候,当前线程(就是在 synchronized方法内部的线程)执行完该方法后,别的线程才能 进入。

2 synchronized块

synchronized 方法的缺陷:若将一个大的方法声明为 synchronized 将会大大影响效率。 Java 为我们提供了更好的解决办法,那就是 synchronized 块。 块可以让我们精确地控制到具体的“成员变量”,缩小同步的范 围,提高效率。

修改线程冲突案例演示

/**
* 账户类
*/
class Account{
    //账号
    private String accountNO;
    //账户余额
    private double balance;
    public Account() {
   }
    public Account(String accountNO, double balance) {
        this.accountNO = accountNO;
        this.balance = balance;
   }
    public String getAccountNO() {
        return accountNO;
   }
    public void setAccountNO(String accountNO) {
        this.accountNO = accountNO;
}
    public double getBalance() {
        return balance;
   }
    public void setBalance(double balance) {
        this.balance = balance;
   }
}
/**
* 取款线程
*/
class DrawThread implements Runnable{
    //账户对象
    private Account account;
    //取款金额
    private double drawMoney;
    public DrawThread(){
   }
    public DrawThread(Account account,double drawMoney){
        this.account = account;
        this.drawMoney = drawMoney;
   }
    /**
     * 取款线程体
     */
    @Override
 public void run() {
        synchronized (this.account){
            //判断当前账户余额是否大于或等于取款金额
            if(this.account.getBalance() >= this.drawMoney){
              System.out.println(Thread.currentThread().getName()+" 取钱成功!突出钞票"+this.drawMoney);
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
                //更新账户余额
              this.account.setBalance(this.account.getBalance() - this.drawMoney);
                System.out.println("\t 余额为:"+this.account.getBalance());
           }else{
              System.out.println(Thread.currentThread().getName()+" 取钱失败,余额不足");
           }
       }
   }
}
public class TestDrawMoneyThread {
    public static void main(String[] args) {
        Account account = new Account("1234",1000);
        new Thread(new DrawThread(account,800),"老公").start();
        new Thread(new DrawThread(account,800),"老婆").start();
   }
}

线程同步的使用

使用this作为线程对象锁

 语法结构:

synchronized(this){
      //同步代码
 }

public  synchronized  void accessVal(int newVal){
    //同步代码
}
/**
* 定义程序员类
*/
class Programmer{
    private String name;
    public Programmer(String name){
        this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
                System.out.println(this.name + " 接通电源");
                Thread.sleep(500);
                System.out.println(this.name + " 按开机按键");
                Thread.sleep(500);
                System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
                System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedException e){
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
                System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
                System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
                System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
public class TestSyncThread {
    public static void main(String[] args) {
        Programmer p = new Programmer("张三");
        new Working1(p).start();
        new Working2(p).start();
   }
}

使用字符串作为线程对象锁

 语法结构:

synchronized(“字符串”){
      //同步代码
 }
/**
* 定义程序员类
*/
class Programmer{
    private String name;
    public Programmer(String name){
        this.name = name;
   }
    /**
     * 打开电脑
  */
    synchronized  public  void computer(){
            try {
              System.out.println(this.name + " 接通电源");
                Thread.sleep(500);
              System.out.println(this.name + " 按开机按键");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
              System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
              System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
              System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
              System.out.println(this.name + " 冲水");
                Thread.sleep(500);
              System.out.println(this.name + " 离开卫生间");
 } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
  this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
        Programmer p = new Programmer("张三");
        Programmer p1 = new Programmer("李四");
        Programmer p2 = new Programmer("王五");
        new WC(p).start();
        new WC(p1).start();
        new WC(p2).start();
   }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/738236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

串口问题案例分享

最近在调试一个新板子的时候&#xff0c;发现一个问题&#xff0c;板子使用的是一个国产的处理器芯片&#xff0c;表现为如果板子232串口的发送和接收与电脑串口连接时&#xff0c;板子可以正常进入系统。 但是如果板子与电脑只接232串口的发送信号&#xff0c;不接232串口的接…

Java入门--字面量

字面量 字面量是指在代码中直接表示特定的常量或值&#xff0c;可以是整数&#xff0c;浮点数&#xff0c;布尔值&#xff0c;字符等 演示 整数和小数 System.out.println(666);//小数System.out.println(99.5);快捷写法&#xff1a;666.sout 加回车 字符 字符必须用单引号…

docker安装es集群(三台)

文章目录 1、防火墙设置&#xff0c;开启所需端口2、创建目录&#xff0c;并更改目录权限3 设置系统参数4 启动5 安装ik分词器6 配置7 安装elasticsearch-head&#xff08;用于访问es&#xff0c;界面化工具&#xff09;8、 修改es中每次返回的数据数量参数&#xff08;默认100…

剑指offer55-II.平衡二叉树

我这个方法比较笨&#xff0c;用的是用的是昨天写的求二叉树深度的方法&#xff0c;先定义dfs求二叉树深度的方法&#xff0c;再定义cur方法&#xff0c;比较左子树和右子树的深度&#xff0c;递归比较每一个子树的左子树和右子树的深度&#xff0c;一旦有一个不平衡就把flag改…

vue3使用Eharts案例

文章目录 安装Eharts代码演示最终效果 安装Eharts 官方快速上手地址 npm install echarts --save代码演示 <script setup> import {onMounted, ref} from "vue"; // import echarts from "echarts"; import * as echarts from echarts; const opt…

聊聊「画图」和工具

经常被问&#xff1a;图怎么画&#xff0c;用啥工具&#xff1f; 01 每次遇到这个问题&#xff0c;脑回路都有一丝丝欢乐的氛围&#xff1b; 并不是问题奇怪&#xff1b; 而是自己对于画图这件事上并不专业&#xff0c;就算是涉及工作上的制图&#xff0c;也没特地去看过任何…

交换机远程登录telnet、SSH、禁止非法用户访问实验

交换机远程登录实验 交换机远程登录实验一、配置Console口登录设备二、配置Telnet远程登录三、Stelnet&#xff08;SSH&#xff09;配置四、远程登录实际中的配置五、禁止非法用户远程登录 交换机远程登录实验 ———————————————————————————————…

解锁数字化转型利器:探秘常用低代码工具大揭秘!

随着数字化转型的深入推进&#xff0c;越来越多的企业开始采用低代码工具来加快应用程序的开发速度。在本文中&#xff0c;我们将介绍常用的低代码工具有哪些&#xff1f;以帮助企业了解并选择适合自己的工具。 1、Zoho Creator Zoho Creator是一款低代码开发平台&#xff0c;提…

Docker配置阿里镜像加速源,超详细

1、首先登入阿里云账号,点击 控制台    2、搜索框查找 容器镜像服务    3、点击 镜像加速器 ,选择对应的操作系统    4、复制加速地址,在系统中配置 默认路径 /etc/docker/daemon.json 5、重启Docker systemctl daemon-reload systemctl restart docker6、验证 当…

【数据结构与算法】力扣:对称二叉树

对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 来源&#xff1a;…

Windows+IDEA+Nginx反向代理本机实现简单集群

先简单创建一个项目&#xff0c;可以是Maven也可以是Spring Initializr&#xff0c;如果是 Maven则需要自己配置启动类 按照目录路径创建controller类 package com.cloud.SR.controller;import org.springframework.beans.factory.annotation.Autowired; import org.springfram…

mac intellij idea配置settings.xml报错解决

今天在配置环境的时候&#xff0c;发现在运行代码的时候不断报错提示maven没有能够成功地被sync&#xff0c;解决方法将以下三点解决了之后&#xff0c;程序最终跑起来了。 1.将maven的版本配置对&#xff0c;之前项目都用的maven-3.8.5这个版本&#xff0c;而我原先用的是mave…

MQ集群搭建

1.⾸先&#xff0c;克隆⼀台IP地址为192.168.230.132的虚拟机&#xff0c;然后参考章节的内 容&#xff0c;在该主机上安装RabbitMQ等环境。再加上之前的虚拟机&#xff0c;这样我们就准备好了两台Linux服 务器。 修改/etc/hosts映射⽂件。 vim /etc/hosts 3.两台Linux主机修改…

python识别登录验证码图片中字符

应用场景&#xff1a;在测试接口时&#xff0c;需要先自动执行登录接口&#xff0c;登录接口需要输入图片中的字符验证码。 实现的步骤主要有以下几步&#xff1a; 一、执行/captcha接口&#xff0c;从接口响应中提取图形验证码的base64编码值&#xff1b; 二、去掉base64编码…

STM32CubeIDE使用示例(STM32CubeMX+STM32CubeIDE+Gcc+JLINK+STM32G030C8T6)

本文简单记录下STM32CubeIDE的使用方法&#xff0c;整体的环境是STM32CubeMXSTM32CubeIDEGccJLINKSTM32G030C8T6&#xff0c;实现的简单测试功能是让STM32G030C8T6板子上的LED闪烁&#xff0c;以STM32G030C8T6 PB4 脚做LED 输出闪烁为例&#xff0c;外部8MHZ 晶振,系统主频64MH…

word 目录创建与提取

前言 word实际上一直在用&#xff0c;但是笔者在写文档都没关注目录的概念&#xff0c;实际上目录就是富文本或markdown编辑器的标题&#xff0c;可以起到跳转的作用。笔者的毕业论文的目录居然还是手打的。 目录创建 实际上word书写的时候就需要设置标题&#xff0c;最近的…

雅思单词量要达到多少才能达到要求?

对于刚开始备考雅思的同学来说&#xff0c;雅思单词是考好雅思的基础&#xff0c;雅思单词量要达到多少才能过关呢&#xff1f;下面为大家介绍一下雅思词汇量的要求。 一、雅思词汇量要求 雅思听力词汇 3000&#xff5e;5000左右&#xff0c;雅思听力是以场景展开的&#xff…

51单片机--定时器与按键控制流水灯模式

文章目录 定时器定时器的介绍定时器的作用定时器框图定时器的工作模式计数器原理图&#xff1a; 中断系统中断程序流程STC89C52的中断资源定时器和中断系统 定时器的相关寄存器TCONTMODTH与TL有关中断的寄存器 按键控制流水灯模式 定时器 定时器的介绍 51单片机上的定时器是一…

率先布局 RWA 赛道,PoseiSwap 成为最具先进性的 DEX

RWA 全称为现实资产通证化&#xff0c;比如股票、期货、美债甚至房产等传统资产。RWA 正在成为加密行业发展的一个全新叙事方向&#xff0c;除了传统商业巨头比如高盛、西门子等开始向该领域深入布局外&#xff0c;以 MakerDAO、Binance、Aave、Maple Finance 等为代表的 Web3 …

MySQL_2

目录 一、函数 1、字符串函数 2、数值函数 3、日期函数 4、流程控制函数 二、约束 1、概念&#xff1a;约束是作用于表中字段上的规则&#xff0c;用于限制存储在表中的数据。 2、目的&#xff1a;保证数据库中数据的正确、有效性和完整性。 3、分类 4、外键约束 4…