当前位置: 首页 > article >正文

多线程2:线程的常用方法、线程安全

欢迎来到“雪碧聊技术”CSDN博客!

在这里,您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者,还是具有一定经验的开发者,相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导,我将不断探索Java的深邃世界,分享最新的技术动态、实战经验以及项目心得。

让我们一同在Java的广阔天地中遨游,携手提升技术能力,共创美好未来!感谢您的关注与支持,期待在“雪碧聊技术”与您共同成长!

目录

一、Thread的常用方法

1、Thread提供的常用方法

2、Thread提供的常见构造器

3、演示

①设置、获取线程名;获取当前线程

②让当前线程休眠1秒

③让线程插队

④借助Thread类的构造器,给线程取名字

4、说明

二、线程安全

1、认识线程安全

①定义

②举例

③总结

2、取钱案例 - 模拟线程安全问题

①案例需求分析

② 编写代码

3、总结


一、Thread的常用方法

1、Thread提供的常用方法

2、Thread提供的常见构造器

3、演示

①设置、获取线程名;获取当前线程

public class Test5 {
    public static void main(String[] args) {
        //目标:搞清楚线程的常用方法
        My_Thread t1 = new My_Thread();
        t1.setName("线程1");//设置t1线程的名称
        System.out.println(t1.getName());//线程默认名称:Thread-索引,如Thread_0
        t1.start();//启动线程2

        My_Thread t2 = new My_Thread();
        t2.setName("线程2");//设置t2线程的名称
        System.out.println(t2.getName());//线程默认名称:Thread-索引,如Thread_0
        t2.start();//启动线程2

        //哪个线程执行此行代码,当前线程就是哪个线程
        Thread thread = Thread.currentThread();//获取当前的线程是哪个
        System.out.println(thread.getName());//当前线程是:主线程main

    }
}

class My_Thread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程输出:"+i);
        }
    }
}

运行结果:

线程1
线程2
main
子线程输出:0
子线程输出:0
子线程输出:1
子线程输出:1
子线程输出:2
子线程输出:2
子线程输出:3
子线程输出:3
子线程输出:4
子线程输出:4

②让当前线程休眠1秒

public class Test6 {
    public static void main(String[] args) {
        //目标:搞清楚Thread类的Sleep方法(线程休眠)
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
            try {
                //让当前线程休眠1秒
                Thread.sleep(1000);//1000ms = 1s
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

③让线程插队

public class Test7 {
    public static void main(String[] args) {
        //目标:搞清楚线程的join方法:线程插队,即调用该方法的线程会先执行完毕
        MyThread t1 = new MyThread("线程1");
        t1.start();

        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName() +"-"+ i);
            if(i==2){
                try {
                    t1.join();//让t1线程先插队执行完毕
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

//1、定义一个子类继承Thread类,成为一个线程类
class MyThread extends Thread{
    public MyThread(String name) {
        super(name);
    }

    //2、重写Thread类的run方法
    public void run() {
        //3、在run方法中编写线程的任务代码(线程要干的活)
        for (int i = 1; i <= 10; i++) {
            System.out.println(Thread.currentThread().getName()+"-" + i);
        }
    }
}

运行结果:

一旦主线程main输出2,那么此时就会让线程1插队执行,等执行完线程1,才会让主线程main继续执行。

因此观察到的现象就是:控制台打印main-2之后,就会发现接着打印线程1的结果,直到打印完所有关于线程1的结果,才会继续打印main的。

线程1-1
main-1
线程1-2
main-2
线程1-3
线程1-4
线程1-5
线程1-6
线程1-7
线程1-8
线程1-9
线程1-10
main-3
main-4
main-5
main-6
main-7
main-8
main-9
main-10

④借助Thread类的构造器,给线程取名字

4、说明

二、线程安全

1、认识线程安全

①定义

        多个线程,同时操作同一个共享资源的时候,可能会出现业务安全问题。

②举例

③总结

2、取钱案例 - 模拟线程安全问题

①案例需求分析

② 编写代码

public class Test8 {
    public static void main(String[] args) {
        //目标:模拟线程安全问题
        //1、设计一个账户类:用于创建小明和小红的共同账户,存入10万
        Account acc = new Account(100000);
        //2、设计线程类:创建小明和小红两个线程,模拟小明和小红两人同时从账户取款10万
        new DrawThread("小明", acc).start();
        new DrawThread("小红", acc).start();
    }
}

//银行账户类
class Account{
    private double money;//账户余额

    //构造器
    public Account(double money) {
        this.money = money;
    }
    //get/set
    public double getMoney() {
        return money;
    }
    public void setMoney(double money) {
        this.money = money;
    }
    //toString
    @Override
    public String toString() {
        return "Account{" +
                "money=" + money +
                '}';
    }
    //成员方法:小明、小红来取钱
    public void drawMoney(double money) {
        //拿到当前取钱的线程名称(小明/小红)
        String name = Thread.currentThread().getName();
        //判断余额是否足够
        if(this.money >= money){
            //余额足够,取钱
            System.out.println(name + "取钱成功,吐出了" + money +"元成功!");
            //更新余额
            this.money -= money;
            //打印当前剩下的账户余额
            System.out.println(name + "取钱成功后,当前余额剩余"+ this.money + "元");
        }else{
            //余额不足
            System.out.println(name + "取钱失败,余额不足");
        }
    }
}

//取钱线程类
class DrawThread extends Thread{
    private Account acc;//记住线程对象要处理的账户对象

    //有参构造器
    public DrawThread(String name, Account acc) {
        super(name);//调用父类Thread类的有参构造器,来进行线程名称的赋值
        this.acc = acc;
    }

    public void run() {
        //小明、小红 取钱
        acc.drawMoney(100000);
    }
}

运行结果:

小明取钱成功,吐出了100000.0元成功!
小红取钱成功,吐出了100000.0元成功!
小明取钱成功后,当前余额剩余0.0元
小红取钱成功后,当前余额剩余-100000.0元

可见此时账户余额为-10万,银行血亏10万元,这就是线程不安全导致的问题。

3、总结

以上就是Thread类的常用方法、线程安全问题,如果想了解更多的线程知识,请关注本博主~~


http://www.kler.cn/a/398351.html

相关文章:

  • 【Linux内核剖析】深入分析inet_init的处理机制
  • C++学习-空指针推荐使用nullptr
  • MySql 日期周处理方式
  • 31DNS设置
  • 【Node.js】使用 Node.js 需要了解多少 JavaScript?
  • 什么是SSL VPN?其中的协议结构是怎样的?
  • 向量元素的修改和删除
  • 数据结构:图(二)---- 最小生成树算法
  • 小程序23-页面的跳转:navigation 组件详解
  • 嵌入式硬件杂谈(二)-芯片输入接入0.1uf电容的本质(退耦电容)
  • 【iOS】iOS的轻量级数据库——FMDB
  • C++11的std::for_each和lambda调用的使用实例
  • 解决Docker环境变量的配置的通用方法
  • 零基础Java第二十期:认识String(二)
  • 论文阅读:Uni-ISP Unifying the Learning of ISPs from Multiple Cameras
  • 自然语言处理技术之细粒度实体识别
  • Qt/C++ 开源控件 可折叠的标签管理控件
  • 使用 Python 和 Py2Neo 构建 Neo4j 管理脚本
  • #开发环境篇:vscode里面登录已同步设置的提示1怎么取消
  • 无法下载element-admin的依赖无法运行
  • 黑马智慧商城项目学习笔记
  • Python+Flask实现搜索引擎,万能搜索框
  • 【GeekBand】C++设计模式笔记13_Flyweight_享元模式
  • 【相关分析方法】MATLAB计算滑动时滞相关系数
  • 【Python】如何设置VSCode中的Pylint,消除各种没有必要的警告
  • 【异常解决】Linux shell报错:-bash: [: ==: 期待一元表达式 解决方法