多线程(总结黑马程序员)

news2024/10/6 22:22:56

一、什么是线程?

  • 是一个程序内部的一条执行流程

多线程是什么?

  • 多条线程由CPU负责调度执行

多线程的创建方式一:继承Thread类

//1.继承Thread类
public class MyThread extends Thread {
    //2.必须重写run方法
    @Override
    public void run() {
        for (int i = 1; i <= 5 ; i++) {
            System.out.println("子线程MyThread输出 :" + i);
        }
    }
}



public class ThreadTest1 {
    //main方法是由一条默认的主线程负责执行
    public static void main(String[] args) {
        //3.创建MyThread线程类的对象代表一个线程
        Thread t = new MyThread();
        //4.启动线程(自动执行run方法)
        t.start();

        for (int i = 1; i <= 5 ; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

多线程的创建方式二:实现Runnable接口

//1.实现Runnable接口
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 5 ; i++) {
            System.out.println("子线程输出:" + i);
        }
    }
}

public class ThreadTest1 {
    public static void main(String[] args) {
        Runnable target = new MyRunnable();
        new Thread(target).start();

        for (int i = 1; i <= 5 ; i++) {
            System.out.println("主线程main输出:" + i);
        }
    }
}

匿名内部类的写法

public class ThreadTest1 {
    public static void main(String[] args) {
        //直接创建Runnable接口的匿名内部类
        Runnable target = new MyRunnable(){
            @Override
            public void run() {
                for (int i = 1; i <= 5 ; i++) {
                    System.out.println("子线程1输出:" + i);
                }
            }
        };
        new Thread(target).start();

        //简化形式1:
        new Thread(new MyRunnable(){
            @Override
            public void run() {
                for (int i = 1; i <= 5 ; i++) {
                    System.out.println("子线程2输出:" + i);
                }
            }
        }).start();

        //简化形式2
        new Thread(() -> {
                for (int i = 1; i <= 5 ; i++) {
                    System.out.println("子线程3

多线程的创建方式三:;利用Callable接口、FutureTask类来实现

//1.让这个类实现Callable接口
public class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }
    //2.重写call方法
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n ; i++) {
            sum += i;
        }
        return "线程求出了1-" + n + "的和是:" + sum;


    }
}

  public static void main(String[] args) throws ExecutionException, InterruptedException {
        //3.创建一个Callable对象
        Callable call = new MyCallable(100);
        //4.把Callable的对象封装成一个FutureTask对象
        //未来对象的作用?
        //1.是一个任务对象,实现了Runnable对象
        //2.可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后
        FutureTask<String> f1 = new FutureTask<>(call);
        new Thread(f1).start();

        Callable<String> call2 = new MyCallable(200);
        FutureTask<String> f2 = new FutureTask<>(call2);
        new Thread(f2).start();


        //6.获取线程执行完毕后返回的结果
        //注意:如果执行到这,假如上面的线程还没有执行完毕
        //这里的代码会暂停,等待上面线程执行完毕后才会获取结果
        String rs = f1.get();
        System.out.println(rs);

        String rs2 = f2.get();
        System.out.println(rs2 );

    }

Thread常用方法

public class ThreadTest1 {
    public static void main(String[] args) {
        MyThread t1 = new MyThread("1号线程");
        t1.start();
        System.out.println(t1.getName());

        MyThread t2 = new MyThread("2号线程");
        t2.start();
        System.out.println(t2.getName());

        //主线程对象的名字
        //哪个线程执行它,它就会得到哪个线程对象
        Thread m = Thread.currentThread();
        m.setName("最diao的线程");
        System.out.println(m.getName());

        for (int i = 1; i <= 5 ; i++) {
            System.out.println(m.getName() + "线程输出:" + i);
        }
    }
}


public class MyThread extends Thread {
    public MyThread(String name) {
        super(name); //为当前线程设置名字
    }

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        for (int i = 1; i <= 3 ; i++) {
            System.out.println();
        }
    }
}

二、线程安全问题 

出现原因:

  • 存在多个线程同时执行
  • 同时访问一个共享资源
  • 存在修改该共享资源

取钱案例

需求:小明和小红有一个共同的账户,余额是10万元,模拟2人同时去取钱10万

  • 测试类
public class ThreadTest {
    public static void main(String[] args) {
        //1.创建一个账户对象,代表两个人的共享账户
        Account acc = new Account("ICBC-110", 100000);
        //2.创建两个线程,分别代表小明 小红,再去同一个账户对象中取钱10万
        new DrawThread(acc,"小明").start();
        new DrawThread(acc,"小红").start();
    }
}
  • 线程类
public class DrawThread extends Thread{
    private  Account acc;

    public DrawThread(Account acc,String name) {
        super(name);
        this.acc = acc;
    }

    @Override
    public void run() {
        //取钱
        acc.drawMoney(100000);
    }
}
  • 账户类
public class Account {

    private String cardId; //卡后
    private double money;  //账户余额

    public Account() {
    }

    public void drawMoney(double money) {
        //先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        //1.判断余额是否够
        if(this.money >= money){
            System.out.println(name + "来取钱" + money + "成功!");
            this.money -= money;
            System.out.println(name + "取钱后,剩余余额:" + this.money);
        }else{
            System.out.println(name + "来取钱,余额不足");
        }
    }

    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

}

三、线程同步

  • 解决线程安全问题的方案

线程同步的思想

  • 让多个线程实现先后依次访问共享资源

常见方案

  • 加锁:每次只允许一个线程加锁,加锁后才能进入访问,访问完毕后自动解锁,然后其他线程才能再加锁进来

方式1:同步代码块

  • 作用:把访问共享资源的核心代码给上锁,保证线程安全
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
public void drawMoney(double money) {
        //先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        //1.判断余额是否够
        //this代表共享资源
        synchronized (this) {
            if(this.money >= money){
                System.out.println(name + "来取钱" + money + "成功!");
                this.money -= money;
                System.out.println(name + "取钱后,剩余余额:" + this.money);
            }else{
                System.out.println(name + "来取钱,余额不足");
            }
        }
    }

方式2:同步方法

  • 作用:把访问共享资源的核心方法给上锁
  • 原理:每次只允许一个线程加锁后进入,执行完毕后自动解锁,其他线程才可以进来执行
 public synchronized void drawMoney(double money) {

}

同步方法底层原理 

  • 如果方法是实例方法:默认用this作为锁的对象
  • 如果方法是静态方法:默认用类名.class作为锁的对象

是同步代码块好还是同步方法好?

  • 范围上:同步代码块锁的范围更小,同步方法锁的范围更大
  • 可读性:同步方法更好

方式3:Lock锁

  • Lock锁是接口,不能直接实例化,可以采用它的实现类ReentrantLock来构建Lock锁对象
 //创建了一个锁对象
    private final Lock lk = new ReentrantLock();


public void drawMoney(double money) {
        //先搞清楚是谁来取钱
        String name = Thread.currentThread().getName();
        try {
            lk.lock(); //加锁
            if(this.money >= money){
                System.out.println(name + "来取钱" + money + "成功!");
                this.money -= money;
                System.out.println(name + "取钱后,剩余余额:" + this.money);
            }else{
                System.out.println(name + "来取钱,余额不足");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lk.unlock();//解锁
        }
    }

四、线程池

什么是线程池?

  • 一个可以复用线程的技术

不使用线程池的原因

  • 创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,严重影响系统的性能

谁代表线程池?

  • 代表线程池的接口:ExEcuatorService

如何得到线程池对象?

 

  • 方式1:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
public class ThreadPoolTest {
    public static void main(String[] args) {
//        public ThreadPoolExecutor(int corePoolSize,
//                                    int maximumPoolSize,
//                                    long keepAliveTime,
//                                    TimeUnit unit,
//                                    BlockingQueue<Runnable> workQueue,
//                                    ThreadFactory threadFactory,
//                                    RejectedExecutionHandler handler) {
        //1.创建一个线程池对象
      ExecutorService pool =   new ThreadPoolExecutor(3,5,8,
                TimeUnit.SECONDS,new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }
}

   //2.使用线程池处理Callable任务
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());

 Executors工具类实现线程池

 //1-2 通过Executors创建线程池对象
      ExecutorService pool = Executors.newFixedThreadPool(3);
      //核心线程数量到底配置多少呢?
      //计算密集型的任务:核心线程数量 = CPU的核数 + 1
      //IO密集型的任务:核心线程数量 = CPU的核数 + 2

五、线程的并发、并行和生命周期

进程

  • 正在运行的程序就是一个独立的进程
  • 进程中的多个线程其实是并发并行执行的

并发的含义

  • 进程中的线程是由CPU调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能执行,CPU会轮询为系统的每个线程服务

并行的理解

  • 在同一个时刻,同时有多个线程在被CPU调度

线程的生命周期

  • 也就是线程从生到死的过程,经历的各种状态及状态转换

JAVA线程的状态

  • 总共定义6种状态
  • 都定义在Thread类的内部枚举类中
public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called {@code Object.wait()}
         * on an object is waiting for another thread to call
         * {@code Object.notify()} or {@code Object.notifyAll()} on
         * that object. A thread that has called {@code Thread.join()}
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

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

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

相关文章

AI 音乐大模型:创新的曙光还是创意产业的阴影?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

课程品牌推广与传播秘籍:让你的课程火爆全网!

如今在线教育平台的竞争愈发激烈&#xff0c;如何让你的课程在茫茫网海中脱颖而出&#xff0c;吸引更多学员的关注和报名&#xff1f; 作为一名手工酸奶品牌的创始人&#xff0c;目前全国复制了100多家门店&#xff0c;很多都是线上授课。而且我自己还有一家传媒公司&#xff…

【C++题解】1670 - 象棋大赛

问题&#xff1a;1670 - 象棋大赛 类型&#xff1a;分支问题 题目描述&#xff1a; 市里要组织象棋大赛&#xff0c;年龄在 8∼30 周岁之间的选手可以报名参赛。为了公平起见&#xff0c;大赛组委会将选手们分了青年组、少年组和儿童组&#xff0c;大赛组委会规定&#xff1a…

heygen的前世今生

heygen 关于徐卓&梁望国内创业&诗云科技成立heygen为什么原班人马在国内做和国外做产品&#xff0c;造成的结果如此迥异&#xff1f;技术原理 关于徐卓&梁望 徐卓本科毕业于同济大学&#xff0c;硕士毕业于卡内基梅隆大学计算机专业&#xff0c;之后在 Snap 工作了…

ITSS案例分享 — 强化网络安全保障水平

某科技有限公司成立于2001年&#xff0c;是中国网络安全产业领跑者&#xff0c;于2000年发力安全业务&#xff0c;在云安全、身份安全、终端安全、态势感知、高级威胁治理&#xff0c;以及威胁情报领域等拥有多项全球领先技术&#xff0c;在核心技术领域持续领跑&#xff1b;同…

【每日刷题】Day70

【每日刷题】Day70 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 922. 按奇偶排序数组 II - 力扣&#xff08;LeetCode&#xff09; 2. 905. 按奇偶排序数组 - 力扣&…

【会议征稿,CPS出版】第四届管理科学和软件工程国际学术会议(ICMSSE 2024,7月19-21)

第四届管理科学和软件工程国际学术会议(ICMSSE 2024)由ACM珠海分会&#xff0c;广州番禺职业技术学院主办&#xff1b;全国区块链行业产教融合共同体&#xff0c;AEIC学术交流中心承办&#xff0c;将于2024年7月19-21日于广州召开。 会议旨在为从事管理与软件工程领域的专家学…

瑞尼克RNK聚四氟乙烯注射器刻度清晰纯净

四氟注射器用于抽取或者注入气体或者液体&#xff0c;四氟注射器由前端带有小孔的针筒以及与之匹配的活塞芯杆组成&#xff0c;用来将少量的液体或其注入到其它方法无法接近的区域或者从那些地方抽出&#xff0c;在芯杆拔出的时候液体或者气体从针筒前端小孔吸入&#xff0c;在…

程控漏电流测试电阻箱的应用

程控漏电流测试电阻箱是用于测量和控制电流的设备&#xff0c;广泛应用于电力系统、电子设备、自动化设备等领域。它的主要功能是通过改变电阻值来控制电流的大小&#xff0c;从而实现对设备的保护和控制。 程控漏电流测试电阻箱在电力系统中有着重要的应用&#xff0c;电力系统…

数据分析第十讲:pandas 应用入门(五)

pandas 应用入门&#xff08;五&#xff09; 我们再来补充一些使用DataFrame做数据分析时会使用到的操作&#xff0c;这些操作不仅常见而且也非常重要。 计算同比环比 我们之前讲过一个统计月度销售额的例子&#xff0c;我们可以通过groupby方法做分组聚合&#xff0c;也可以…

火爆全网 LLM大模型教程:从零开始构建大语言模型,git突破18K标星

什么&#xff01;一本书的Github仓库居然有18.5k的星标&#xff01;&#xff08;这含金量不必多说&#xff09; 对GPT大模型感兴趣的有福了&#xff01;这本书的名字叫 《Build a Large Language Model (From Scratch)》 也就是 从零开始构建大语言模型&#xff01; 虽然这是一…

软件构造 | Equality in ADT and OOP

软件构造 | Equality in ADT and OOP &#x1f9c7;1 Three ways to regard equality 1.1 Using AF to define the equality ADT是对数据的抽象&#xff0c; 体现为一组对数据的操作 抽象函数AF&#xff1a;内部表示→抽象表示 基于抽象函数AF定义ADT的等价操作&#xff0…

MySQL----事务的隔离级别(附带每一级别实例截图)

先来回顾一下事务并发可能存在的三大问题&#xff1a; 脏读&#xff08;Dirty Read&#xff09;–不能接受 一个事务读取了另一个事务未提交的数据。例如当事务A和事务B并发执行时&#xff0c;当事务A更新后&#xff0c;事务B查询读取到A尚未提交的数据&#xff0c;此时事务A…

探索客户端-服务器架构:网络应用和分布式系统的基石

目录 前言1 客户端-服务器架构概述1.1 客户端的角色1.2 服务器的角色 2 客户端-服务器架构的工作原理3 客户端-服务器架构的应用4 客户端-服务器架构的优缺点4.1 优点方面4.2 缺点方面 5 客户端-服务器架构的未来发展结语 前言 在当今信息技术飞速发展的时代&#xff0c;客户端…

【数据结构】第十八弹---C语言实现堆排序

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 目录 1、堆排序 1.1、基本思想 1.2、初步代码实现 1.3、代码优化 1.4、代码测试 总结 1、堆排序 在博主数据结构第十二弹---堆的应用有详细讲解堆…

【SpringMVC】第1-7章

第1章 初始SpringMVC 1.1 学习本套教程前的知识储备 JavaSEHTMLCSSJavaScriptVueAJAX axiosThymeleafServletMavenSpring 1.2 什么是MVC MVC架构模式相关课程&#xff0c;在老杜的JavaWeb课程中已经详细的讲解了&#xff0c;如果没有学过的&#xff0c;可以看这个视频&…

kafka学习笔记07

Kafka高可用集群搭建节点需求规划 开放端口。 Kafka高可用集群之zookeeper集群搭建环境准备 删除之前的kafka和zookeeper。 重新进行环境部署&#xff1a; 我们解压我们的zookeeper: 编辑第一个zookeeper的配置文件: 我们重复类似的操作&#xff0c;创建三个zookeeper节点: 记…

最新暑假带刷规划:50天吃透660+880!

现在只刷一本题集根本不够 去做做24年的考研真题卷就什么都明白了&#xff0c;24年的卷子就是典型的知识点多&#xff0c;杂&#xff0c;计算量大。 而现在市面上的任何一本题集&#xff0c;都无法做到包含所有的知识点&#xff0c;毕竟版面有限&#xff01; 所以&#xff0…

Python+Pytest+Yaml+Allure接口自动化测试框架详解

PythonPytestYamlAllure整体框架目录&#xff08;源代码请等下篇&#xff09; 框架详解 common:公共方法包 –get_path.py:获取文件路径方法 –logger_util.py:输出日志方法 –parameters_until.py&#xff1a;传参方式方法封装 –requests_util.py&#xff1a;请求方式方法封…

《人工智能导论》书面作业

第 1 章&#xff1a;绪论 1、分别解释人工智能的三个主要学派的代表人物和主要思想&#xff0c;并给出每个学派的一个实际应用实例。 符号主义&#xff08;Symbolists 或 逻辑主义&#xff09;&#xff1a; 代表人物&#xff1a;马文闵斯基&#xff08;Marvin Minsky&#xf…