【韩顺平零基础学java】第17章补充笔记记录

news2024/11/13 9:50:55

1.线程终止

线程完成任务后会自动退出
或者可以使用变量来控制run方法退出的方式终止线程,即通知方式

【例】Threadexit
启动一个线程T。要求在main方法中终止线程T


public class ThreadExit_ {
    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        t1.start();

        //如果希望main线程去控制t1 线程的终止, 必须可以修改 loop
        //让t1 退出run方法,从而终止 t1线程 -> 通知方式

        //让主线程休眠 10 秒,再通知 t1线程退出
        System.out.println("main线程休眠10s...");
        Thread.sleep(10 * 1000);
        t1.setLoop(false);
    }
}

class T extends Thread {
    private int count = 0;
    //设置一个控制变量
    private boolean loop = true;
    @Override
    public void run() {
        while (loop) {

            try {
                Thread.sleep(50);// 让当前线程休眠50ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("T 运行中...." + (++count));
        }

    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

注意:在哪个线程里面调用sleep()方法就阻塞哪个线程。

参考:
https://blog.csdn.net/Weixiaohuai/article/details/83994146

2.线程常用方法

在这里插入图片描述
在这里插入图片描述
yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

jion()方法:线程实例的join()方法可以使得一个线程在另一个线程结束后再执行,即也就是说使得当前线程可以阻塞其他线程执行;

public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {

        T2 t2 = new T2();
        t2.start();

        for(int i = 1; i <= 20; i++) {
            Thread.sleep(1000);
            System.out.println("主线程(小弟) 吃了 " + i  + " 包子");
            if(i == 5) {
                System.out.println("主线程(小弟) 让 子线程(老大) 先吃");
                //join, 线程插队
                //t2.join();// 这里相当于让t2 线程先执行完毕
                Thread.yield();//礼让,不一定成功..
                System.out.println("线程(老大) 吃完了 主线程(小弟) 接着吃..");
            }

        }
    }
}

class T2 extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            try {
                Thread.sleep(1000);//休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程(老大) 吃了 " + i +  " 包子");
        }
    }
}


在这里插入图片描述

3.Synchronized

并发(concurrency) 并行(parallelism)

package com.hspedu.syn;

public class temp {
    public static void main(String[] args) {

        //测试一把
        SellTicket09 sellTicket09 = new SellTicket09();
        new Thread(sellTicket09).start();//第1个线程-窗口
        new Thread(sellTicket09).start();//第2个线程-窗口
        new Thread(sellTicket09).start();//第3个线程-窗口

    }
}


//实现接口方式, 使用synchronized实现线程同步
class SellTicket09 implements Runnable {
    private int ticketNum = 100;//让多个线程共享 ticketNum
    private boolean loop = true;//控制run方法变量


    public synchronized void sell() { //同步方法, 在同一时刻, 只能有一个线程来执行sell方法

            if (ticketNum <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }

            //休眠50毫秒, 模拟
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口 " + Thread.currentThread().getName() + " 售出一张票"
                    + " 剩余票数=" + (--ticketNum));//1 - 0 - -1  - -2
        }

    @Override
    public void run() {
        while (loop) {

            sell();//sell方法是一共同步方法
        }
    }
}

参考
https://cloud.tencent.com/developer/article/2330704

4.互斥锁(死锁)

在这里插入图片描述

public class DeadLock_ {
    public static void main(String[] args) {
        //模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        A.setName("A线程");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("B线程");
        A.start();
        B.start();
    }
}


//线程
class DeadLockDemo extends Thread {
    static Object o1 = new Object();// 保证多线程,共享一个对象,这里使用static
    static Object o2 = new Object();
    boolean flag;

    public DeadLockDemo(boolean flag) {//构造器
        this.flag = flag;
    }

    @Override
    public void run() {

        //下面业务逻辑的分析
        //1. 如果flag 为 T, 线程A 就会先得到/持有 o1 对象锁, 然后尝试去获取 o2 对象锁
        //2. 如果线程A 得不到 o2 对象锁,就会Blocked
        //3. 如果flag 为 F, 线程B 就会先得到/持有 o2 对象锁, 然后尝试去获取 o1 对象锁
        //4. 如果线程B 得不到 o1 对象锁,就会Blocked
        if (flag) {
            synchronized (o1) {//对象互斥锁, 下面就是同步代码
                System.out.println(Thread.currentThread().getName() + " 进入1");
                synchronized (o2) { // 这里获得li对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入2");
                }
                
            }
        } else {
            synchronized (o2) {
                System.out.println(Thread.currentThread().getName() + " 进入3");
                synchronized (o1) { // 这里获得li对象的监视权
                    System.out.println(Thread.currentThread().getName() + " 进入4");
                }
            }
        }
    }
}


在这里插入图片描述

5.homework

在这里插入图片描述

package com.hspedu.homework;

import java.util.Scanner;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Homework01 {
    public static void main(String[] args) {
        A a = new A();
        B b = new B(a);//一定要注意.
        a.start();
        b.start();
    }
}

//创建A线程类
class A extends Thread {
    private boolean loop = true;

    @Override
    public void run() {
        //输出1-100数字
        while (loop) {
            System.out.println((int)(Math.random() * 100 + 1));
            //休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("a线程退出...");

    }

    public void setLoop(boolean loop) {//可以修改loop变量
        this.loop = loop;
    }
}

//直到第2个线程从键盘读取了“Q”命令
class B extends Thread {
    private A a;
    private Scanner scanner = new Scanner(System.in);

    public B(A a) {//构造器中,直接传入A类对象
        this.a = a;
    }

    @Override
    public void run() {
        while (true) {
            //接收到用户的输入
            System.out.println("请输入你指令(Q)表示退出:");
            char key = scanner.next().toUpperCase().charAt(0);
            if(key == 'Q') {
                //以通知的方式结束a线程
                a.setLoop(false);
                System.out.println("b线程退出.");
                break;
            }
        }
    }
}

在这里插入图片描述

package com.hspedu.homework;

/**
 * @author 韩顺平
 * @version 1.0
 */
public class Homework02 {
    public static void main(String[] args) {
        T t = new T();
        Thread thread1 = new Thread(t);
        thread1.setName("t1");
        Thread thread2 = new Thread(t);
        thread2.setName("t2");
        thread1.start();
        thread2.start();
    }
}

//编程取款的线程
//1.因为这里涉及到多个线程共享资源,所以我们使用实现Runnable方式
//2. 每次取出 1000
class T implements  Runnable {
    private int money = 10000;

    @Override
    public void run() {
        while (true) {

            //解读
            //1. 这里使用 synchronized 实现了线程同步
            //2. 当多个线程执行到这里时,就会去争夺 this对象锁
            //3. 哪个线程争夺到(获取)this对象锁,就执行 synchronized 代码块, 执行完后,会释放this对象锁
            //4. 争夺不到this对象锁,就blocked ,准备继续争夺
            //5. this对象锁是非公平锁.

            synchronized (this) {//
                //判断余额是否够
                if (money < 1000) {
                    System.out.println("余额不足");
                    break;
                }

                money -= 1000;
                System.out.println(Thread.currentThread().getName() + " 取出了1000 当前余额=" + money);
            }

            //休眠1s
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

常见的线程安全相关的面试题

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

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

相关文章

网络故障处理及分析工具:Wireshark和Tcpdump集成

Wireshark 是一款免费的开源数据包嗅探器和网络协议分析器&#xff0c;已成为网络故障排除、分析和安全&#xff08;双向&#xff09;中不可或缺的工具。 本文深入探讨了充分利用 Wireshark 的功能、用途和实用技巧。 无论您是开发人员、安全专家&#xff0c;还是只是对网络操…

Unity格斗游戏,两个角色之间互相锁定对方,做圆周运动

1&#xff0c;灵感来源 今天手头的工作忙完了&#xff0c;就等着服务器那边完活&#xff0c;于是开始研究同步问题。 正好想到之前想做的&#xff0c;两个小人对线PK&#xff0c;便有了这篇文章。 2&#xff0c;要实现的效果 如图所示&#xff0c;两个小人可以互相锁定&…

RuoYi-后端管理项目入门篇1

目录 前提准备 下载若依前后端 Gitee 地址 准备环境 后端数据库导入 1 克隆完成 若依后端管理后端 Gitte 地址 :若依/RuoYi-Vue 2.1 创建Data Source数据源 2.2 填写好对应的数据库User 和 Password 点击Apply 2.3 新建一个Schema 2.4 填写对应数据库名称 这边演示写的…

linux shell脚本编程(分支语句、循环语句)

一、分支语句 1、语法结构 : if 表达式 then 命令表 fi 如果表达式为真 , 则执行命令表中的命令 ; 否则退出 if 语句 , 即执行 fi 后面的语句。 if 和 fi 是条件语句的语句括号 , 必须成对使用 ;命令表中的命令可以是一条 , 也可以是若干条。 2、语法结构为 : if 表达式 t…

Flink源码学习资料

Flink系列文档脑图 由于源码分析系列文档较多&#xff0c;本人绘制了Flink文档脑图。和下面的文档目录对应。各位读者可以选择自己感兴趣的模块阅读并参与讨论。 此脑图不定期更新中…… 文章目录 以下是本人Flink 源码分析系列文档目录&#xff0c;欢迎大家查阅和参与讨论。…

leetcode日记(42)螺旋矩阵

我使用的是递归&#xff0c;每次递归遍历一圈矩阵&#xff0c;将遍历结果塞进结果vector中&#xff0c;每次遍历修改上下左右边界&#xff0c;直至遍历后其中两边界重合或交错。 class Solution { public:vector<int> spiralOrder(vector<vector<int>>&…

MySQL双主双从实现方式

双主双从&#xff08;MM-SS&#xff09; 前言 避免单一主服务器宕机&#xff0c;集群写入能力缺失 从 1 复制 主1 &#xff0c;从 2 复制 主 2 主 1 复制 主 2&#xff0c;主 2 复制主 1 也就是 主 1 和主 2 互为主从。主1主2互为主从&#xff0c; 是为了以下情景&#xff0c…

Fork_Join模式:分治和Work-Stealing的完美结合

引言 在计算机科学领域&#xff0c;解决大规模数据和复杂计算任务的需求促使了并行计算模型的发展。Fork/Join模式以其独特的分治和Work-Stealing结合的方式&#xff0c;成为解决可分解并行问题的一项卓越选择。本文将重点探讨Fork/Join模式中分治和Work-Stealing的关键优势&a…

【网络】掌握网络基础概念

文章目录 OSI七层模型TCP/IP五层&#xff08;或四层&#xff09;模型为什么要有TCP/IP协议网络传输的基本流程网络传输流程图数据包封装和分用 网络中的地址管理IP地址Mac地址比较IP地址和Mac地址 OSI七层模型 OSI即Open System Interconnection,开发系统互连。OSI七层模型是一…

电气电工增加收入需规避的16大陷阱

电工接线是电气工程中非常重要的环节&#xff0c;为什么实施项目之后&#xff0c;存在电工叫苦&#xff0c;老板说亏&#xff0c;这到底是什么原因&#xff1f;是什么影响了电工的效率&#xff0c;阻碍了电工收入的增加&#xff1f; 下面我们汇总一下平时在项目中遇到的陷阱&a…

spring核心内容基本解读、spring中IOC控制反转入门案例,debug带你剖析Spring容器机制和结构(图文讲解,简单易懂)。

目录 1.spring核心内容大概解读 2.spring的IOC(控制反转容器机制剖析) 2.1 来份快速入门案例 2.2 debug剖析spring容器的机制和结构 1.spring核心内容大概解读 1. 在线文档 : https://docs.spring.io/spring-framework/docs/current/reference/html/ 2. 离 线 文 档 …

STM32智能健康监测系统教程

目录 引言环境准备智能健康监测系统基础代码实现&#xff1a;实现智能健康监测系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;健康监测与管理问题解决方案与优化收尾与总结 1. 引言 智能健康监测系统通…

SDXL 1.0 下载和部署

SD XL 1.0 重磅更新&#xff01;免费开源可商用&#xff08;附在线使用本地部署教程&#xff09; - 优设网 - 学设计上优设 三、本地部署 SDXL 1.0 SDXL 1.0 的源文件已经在 Huggingface 上开源了&#xff0c;我们可以通过 Stable Diffusion WebUI 在本地免费使用 SDXL 1.0&am…

[C/C++入门][ifelse]19、制作一个简单计算器

简单的方法 我们将假设用户输入两个数字和一个运算符&#xff08;、-、*、/&#xff09;&#xff0c;然后根据所选的运算符执行相应的操作。 #include <iostream> using namespace std;int main() {double num1, num2;char op;cout << "输入 (,-,*,/): &quo…

python项目为什么用WSGI

小背景 Java用的时间久了&#xff0c;web项目启动的时候直接启动主程序就行&#xff0c;因为spring web项目内置了Tomcat web服务器&#xff0c;服务器的配置一般也是采用默认的配置&#xff0c;所以很少关注底层实现&#xff0c;关注点主要在应用程序功能。 初学python的时候…

DDei在线设计器-HTML渲染

Html渲染 HtmlViewer插件通过将一个外部DIV附着在图形控件上&#xff0c;从而改变原有图形的显示方式。允许使用者自己定义HTML通过HTML元素。本示例演示了通过Html来扩展渲染图形&#xff0c;从而获得更加丰富的图形展现。 通常情况下&#xff0c;我们创建的图形控件&#xff…

Wireshark抓取HTTP

HTTP请求响应 使用wireshark抓取 本地机器是192.168.33.195&#xff0c;远程机器是192.168.32.129&#xff0c;远程HTTP服务端口是9005 TCP/IP实际共分为4层&#xff0c;抓包信息中可以看到各层的数据&#xff0c;最上面的数据帧包含了所有数据。 附&#xff1a;抓取本地H…

【Harmony】SCU暑期实训鸿蒙开发学习日记Day2

目录 Git 参考文章 常用操作 ArkTS的网络编程 Http编程 发送请求 GET POST 处理响应 JSON数据解析 处理响应头 错误处理 Web组件 用生命周期钩子实现登录验证功能 思路 代码示例 解读 纯记录学习日记&#xff0c;杂乱&#xff0c;误点的师傅可以掉了&#x1…

体验智慧校园学工管理的社团类型功能

在智慧校园学工管理的框架下&#xff0c;社团类型的精细化管理成为了激发学生兴趣、促进社团多样性与规范性的关键。这一功能的核心在于构建一个清晰的社团分类体系&#xff0c;确保每一种社团都能在其所属领域内蓬勃发展&#xff0c;同时&#xff0c;也便于校园管理者进行有效…

C#与C++交互开发系列(一):引言:为什么需要C#与C++交互开发

C#与C交互开发系列&#xff08;一&#xff09;&#xff1a;引言&#xff1a;为什么需要C#与C交互开发 欢迎来到C#与C交互开发系列博客的第一篇。在这个系列中&#xff0c;我们将探讨如何在C#与C之间实现互操作性&#xff0c;并逐步深入理解其应用场景和技术实现。本文将介绍什么…