Java之多线程初阶2

目录

一.上节内容复习

1.进程和线程的区别

2.创建线程的四种方式

二.多线程的优点的代码展示

1.多线程的优点

2.代码实现

三.Thread类常用的方法

1.Thread类中的构造方法

2.Thread类中的属性

1.为线程命名并获取线程的名字

2.演示isDaemon()

3.演示isAlive()

4.演示getState()

3.Thread类中的方法

1.启动一个线程---start()方法

2.等待一个线程---join()方法

3.中断一个线程----interrupt()方法

3.获取当前线程

4.休眠当前线

5.主动让出CPU---yield()方法


一.上节内容复习

上节内容指路:Java之多线程初阶

1.进程和线程的区别

1.进程中至少包含一个线程(主线程)

2.进程是申请计算机资源的最小单位

3.线程是CPU调度的最小单位

4.进程之间是相互隔离的,线程是使用的是进程统一申请来的资源,之间可以相互影响

2.创建线程的四种方式

1.继承Thread类并重写run()方法

2.实现Runnable接口并重写run()方法

3.通过匿名内部类创建Thread和实现Runnable

4.通过Lambda表达式实现一个线程

二.多线程的优点的代码展示

1.多线程的优点

通过上一节的学习我们知道多线程可以充分利用CPU的资源,提高程序的运行效率

2.代码实现

public class Demo6_10B {
    public static void main(String[] args) {
        serial();
        concurrent();

    }

    public static long COUNT = 10_0000_0000L;

    //串行执行10亿次的自增
    public static void serial() {
        long start = System.currentTimeMillis();
        long a = 0L;
        for (int i = 0; i < COUNT; i++) {
            a++;
        }
        long b = 0L;
        for (int i = 0; i < COUNT; i++) {
            b++;
        }
        long end = System.currentTimeMillis();

        System.out.println("串行的总耗时为:" + (end - start) + " ms");

    }

    //并行执行10亿次的自增
    public static void concurrent() {
        long start = System.currentTimeMillis();

        Thread thread1=new Thread(()->{
            long a=0L;
            for (int i = 0; i < COUNT; i++) {
                a++;
            }
        });
        Thread thread2=new Thread(()->{
            long a=0L;
            for (int i = 0; i < COUNT; i++) {
                a++;
            }
        });
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        long end = System.currentTimeMillis();
        System.out.println("并行的总耗时为:" + (end - start) + " ms");
        
    }
}

注意:并行代码进行实现的时候一定要加 thread1.join();和 thread2.join();这两段代码,join()方法的作用是等待线程执行完毕之后,继续执行下面的代码.如果我们没有这两段代码的话,可能会发生如下情况:两个线程的自增操作还没有完成,主线程(main)线程已经执行完毕,也就是直接打印最终执行的总耗时,正确的耗时的结果应该为串行耗时的一半多.

这里没有加join()代码执行的结果,可以看到主线程执行完毕,线程1和线程2还没有执行完毕.

加join()打印结果:

 我们多执行几次代码,发现每一次并行的耗时都是串行耗时的一半多一些,那么为什么不是一半呢?其实仔细思考我们不难想出:线程的创建和销毁也是需要一定时间的,因此总是一半多一些.

接下来我们将COUNT的值改小点,比如改到COUNT=10_000L,这个时候我们再执行

发现串行的总耗时比并行的总耗时还要短,因此我们可以大胆推测,并不是所有的场景下多线程的效率都是最高的,当我们的运算量很小的时候,创建线程的时间比代码运行的时间还短,这样子显然是不适合用多线程的.

三.Thread类常用的方法

1.Thread类中的构造方法

方法说明
Thread()创建一个线程对象
Thread(String name)创建一个线程对象,并为它命名
Thread(Runnable target)使用Runnable对象创建线程
Thread(Runnable target,String name)使用Runnable对象创建线程,并命名
【了解】 Thread(ThreadGroup group,
Runnable target)
线程可以被用来分组管理,分好的组即为线程组,这 个目前我们了解即可

Thread t1 = new Thread();

Thread t2 = new Thread ( new MyRunnable ());
Thread t3 = new Thread ( " 这是线程名 " );
Thread t4 = new Thread ( new MyRunnable (), "这是线程名" );

2.Thread类中的属性

属性
获取方法
ID
getId()
名称 getName()
状态 getState()
优先级 getPriority()
是否后台线程 isDaemon()
是否存活 isAlive()
是否被中断 isInterrupted()

1.为线程命名并获取线程的名字

public class Demo7_ThreadName {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println(Thread.currentThread().getName() + ":hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }, "这是thread线程");
        thread.start();

    }
}

 在jconsole中查看线程的名字

 当我们不执行线程名字的时候,系统会自动生成线程名,从Thread0开始依次向后进行生成

2.演示isDaemon()

我们之前使用的线程都是前台线程,因为创建线程之后默认都是前台线程,必须手动设置成为后台线程,我们通过        thread.setDaemon(true);代码将这个进行设置为后台进程

public class Demo8_Daemon {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println(Thread.currentThread().getName() + ":hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        //手动设置为后台线程,默认为false,也就是前台线程
        thread.setDaemon(true);
        System.out.println("是否存活:" + thread.isAlive());
        // 启动线程
        thread.start();
        // 休眠一会,确保系统PCB创建成功
        Thread.sleep(500);
        System.out.println("是否存活:" + thread.isAlive());
        System.out.println("main线程执行完成");
        System.out.println("是否存活:" + thread.isAlive());
        
    }
}

打印结果如下:

 我们可以看出来,随着main方法的执行完毕,程序也进行了关闭

和前台进程进行对比,前台进程打印的结果如下:

 因此我们可以总结出前台进程和后台进程运行的场景

前台进程:在一些需要需要精确业务,容错率低的事务中采用前台进程,如银行转账,要确保转账线程的完成.

后台进程:在一些容错率高的任务,可以采用,如微信的步数计算,并不需要精确计算你精确的步数,不影响主线程的关闭..

3.演示isAlive()

public class Demo9_IsAlive {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            int cnt = 0;
            while (true) {
                System.out.println("hello thread.....");
                cnt++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (cnt == 5)
                    break;
            }
        });

        System.out.println("是否存活:" + thread.isAlive());
        // 启动线程
        thread.start();

        System.out.println("是否存活:" + thread.isAlive());
        //等待线程执行完毕
        try {
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("是否存活:" + thread.isAlive());

    }
}

打印的结果如下:

由此我们可以总结得出:isAlive()方法是判断系统线程(PCB)是否存活,并不是我们new出来的Thread对象

4.演示getState()

  • NEW:创建一个Java线程(对象),但还没有调用start()方法,也就是没有参与CPU调度,此时就是一个Java的对象
  • RUNNABLE: 运行或在就绪队列中(PCB的就绪队列)
  • BLOCKED: 等待锁的时候进入堵塞状态(synchronized)
  • WAITING: 没有时间限制的等待
  • TIMED_WAITING: 等待一段时间(有时间限制的等待)(过时不候)
  • TERMINATED:线程执行完成,PCB在操作系统中已经销毁,但是JAVA对象还在

线程状态之间的转换图

 这里来观察三种状态NEW-->TIME_WAITING-->TERMINATED

public class Demo14_State {
    public static void main(String[] args) {
        Thread thread=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println("启动之前的状态:"+thread.getState());

        thread.start();
        //等待线程的创建
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("启动之后的状态:"+thread.getState());
        //等待线程结束
        try {
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("线程完成之后的状态:"+thread.getState());

    }
}

打印的结果为: 

  这里来观察三种状态NEW-->RUNNABLE-->TERMINATED

public class Demo14_State {
    public static void main(String[] args) {
        Thread thread=new Thread(()->{
            for(long i=0;i<10000000000L;++i){

            }
        });
        System.out.println("启动之前的状态:"+thread.getState());

        thread.start();
        //等待线程的创建
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("启动之后的状态:"+thread.getState());
        //等待线程结束
        try {
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("线程完成之后的状态:"+thread.getState());

    }
}

打印的结果如下:

具体堵塞的状态BLOCK(synchronized具体的用法下一节)

public class Demo16_State2 {

    public static void main(String[] args) {
        final Object object = new Object();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                //此时object对象就是锁
                synchronized (object) {
                    while (true) {
                        System.out.println("张三");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "t1");
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (object) {
                    System.out.println("李四");
                    System.out.println("hehe");
                }
            }
        }, "t2");
        t2.start();
        //等待线程的创建
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("线程1此时的状态:"+t1.getState());
        System.out.println("线程2此时的状态:"+t2.getState());

    }

}

因为线程一的状态处以sleep(1000),所以他现在是TIMED_WAITING,因为线程一拿到了锁是object对象,而线程二也没有拿到,需要等到线程一释放锁才可以继续进行,所以线程二的状态为BLOCK

将上面代码的Thread.sleep(1000)代码改换为object.wait();代码可以观察到WAIT状态

具体的打印如下,可以看到线程一处在WAIT状态,每一继续向下打印,并且锁也没有释放,所以线程二一致处在BLOCK状态

结论:

1.BLOCKED 表示等待获取锁, WAITING TIMED_WAITING 表示等待其他线程发来通知.
2.TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒

3.Thread类中的方法

1.启动一个线程---start()方法

我们前面一节讲过start方法,通过调用start0()本地方法来启动一个线程

有上面的基础,这里我们来分析一下start()方法和run()方法的区别

1.start()方法是真正申请一个系统线程,run()方法是定义线程要执行的任务

2.直接调用run()方法,不会去申请一个真正的系统线程(PCB),而是调用对象的方法

调用start()方法,JVM会调用本地方法去申请一个真正的系统线程(PCB),并执行run()方法中的逻辑

接下来通过下段代码来更好的理解:

public class Demo13_StartRun {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println("hello thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });
        thread.run();
//        thread.start();
        System.out.println("线程状态:" + thread.getState());
        System.out.println("主线程结束");

    }
}

调用run()方法打印的结果:

调用start()方法打印的结果:

可以观察到调用run()方法根本不会打印主线程结束,而调用start()方法会打印.

2.等待一个线程---join()方法

join()方法的作用:等待当前线程结束,进行到下一步的工作

方法说明
public void join()
等待线程结束
public void join(long millis) 等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos) 同理,但可以更高精度
public class Demo12_Join {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; ++i) {
                System.out.println("hello,thread " + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();

        System.out.println("join之前,线程状态:" + thread.getState());
        System.out.println("join之前,是否存活:" + thread.isAlive());
        // 使用join等待thread线程结束
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("join之后,线程状态:" + thread.getState());
        System.out.println("join之后,是否存活:" + thread.isAlive());
        System.out.println("主线程执行完成。");


    }
}

打印的结果:

3.中断一个线程----interrupt()方法

线程的中断:停止或者中断当前线程的任务.

实现线程的中断有如下两种方式

1.通过是否中断的标志位(手动)

通过isQuit的修改来中断线程

public class Demo10_Interrupted {
    public static boolean isQuit = false;

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!isQuit) {
                System.out.println("hello thread...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            System.out.println("线程任务完成");
        });

        // 启动线程
        thread.start();
        //让子线程先执行一段时间
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //通过修改isQuit来中断线程
        isQuit = true;
        //让子线程先结束
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("主线程任务完成");

    }
}

打印的结果如下:

2.通过Thread类提供的interrupted()方法来中断线程

public class Demo11_Interrupted02 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello thread...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            System.out.println("是否中断:" + Thread.currentThread().isInterrupted());
            System.out.println("线程任务完成");
        });

        // 启动线程
        thread.start();
        //让子线程先执行一段时间
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //中断线程,修改Thread的中断标志
        thread.interrupt();
        //让子线程先结束
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("主线程任务完成");
    }
}

当我们采用如上的代码来进行线程的中断,打印的结果如下:

 因为当前子线程的状态处于sleep()或者堵塞状态,这个时候线程中断的状态是sleep()或者堵塞状态,比如现实情境下张三学习1秒,睡觉1分钟,我们打断张三的状态,大概率张三在睡觉,我们打断的是张三睡觉的状态.

那么到底该怎么进行线程的中断呢?我们看到打印的结果的时候看到有异常的捕获,其实我们可以想到在异常捕获的时候加上一个break即可.

public class Demo11_Interrupted02 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello thread...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }

            }
            System.out.println("是否中断:" + Thread.currentThread().isInterrupted());
            System.out.println("线程任务完成");
        });

        // 启动线程
        thread.start();
        //让子线程先执行一段时间
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //中断线程,修改Thread的中断标志
        thread.interrupt();
        //让子线程先结束
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("主线程任务完成");
    }
}

3.获取当前线程

方法说明
public static Thread currentThread();
返回当前线程对象的引用

public class ThreadDemo {
    public static void main(String[] args) {
        //获取到的是主线程main
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
   }
}

4.休眠当前线

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

sleep方法只是保证在这个时间段内进行休眠,不被调度到CPU运行,并不是很精准

5.主动让出CPU---yield()方法

public class Demo15_Yield {
    public static void main(String[] args) {
        Thread thread1=new Thread(()->{
            while (true){
                System.out.println("我是张三");
//                Thread.yield();
            }
        });
        Thread thread2=new Thread(()->{
            while (true){
                System.out.println("我是李四");
            }
        });
        thread1.start();
        thread2.start();

    }
}

当注释掉yield()方法的打印是这样的,基本上都是一半一半的打印.

当使用yield()方法,明显李四的打印大于张三

结论:yield 不改变线程的状态, 但是会重新去排队

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【操作系统OS】学习笔记第三章 内存管理【哈工大李治军老师】

基于本人观看学习 哈工大李治军老师主讲的操作系统课程 所做的笔记&#xff0c;仅进行交流分享。 特此鸣谢李治军老师&#xff0c;操作系统的神作&#xff01; 如果本篇笔记帮助到了你&#xff0c;还请点赞 关注 支持一下 ♡>&#x16966;<)!! 主页专栏有更多&#xff0…

数字化战略,如何解读企业财务报表

01 财务数字化管理 第一&#xff0c;财务基本信息化建设。比如财务系统、财务共享中心等通过数字化的手段提升财务会计核算、财务流程管理效率&#xff0c;解决流程性管理的问题。 第二&#xff0c;利用各类商业智能 BI 分析、数据分析的手段把企业的所有行为都进行量化对比&…

vue 水印组件

效果图展示 Watermark 参数说明类型默认值版本width水印的宽度&#xff0c;content 的默认值为自身的宽度number120height水印的高度&#xff0c;content 的默认值为自身的高度number64rotate水印绘制时&#xff0c;旋转的角度&#xff0c;单位 number-22zIndex追加的水印元素…

【计算机图形学基础教程】MFC基本绘图函数2

MFC基本绘图函数 绘图工具类 CGdiObject类&#xff1a;GDI绘图工具的基类CBitmap类&#xff1a;封装了GDI画刷&#xff0c;可以选作设备上下文的当前画刷&#xff0c;用于填充图形的内部CFont类&#xff1a;封装了GDI字体&#xff0c;可以选作设备上下文的当前字体CPalette类…

selenium——unittest框架

目录 一、unittest框架基本介绍二、unittest框架解析三、unittest框架使用方法1.测试固件2.测试套件3.用例的执行顺序4.忽略测试用例中的方法5.unittest断言6.HTML报告生成 一、unittest框架基本介绍 在进行selenium IDE脚本录制导出的脚本中&#xff0c;我们发现其中多了很多…

基于 EKS Fargate 搭建微服务性能分析系统

背景 近期 Amazon Fargate 在中国区正式落地&#xff0c;因 Fargate 使用 Serverless 架构&#xff0c;更加适合对性能要求不敏感的服务使用&#xff0c;Pyroscope 是一款基于 Golang 开发的应用程序性能分析工具&#xff0c;Pyroscope 的服务端为无状态服务且性能要求不敏感&…

mysql数据迁移与同步常用解决方案总结

目录 一、前言 二、数据迁移场景 2.1 整库迁移 2.2 表数据迁移 2.3 mysql版本变更 2.4 mysql数据迁移至其他存储介质 2.5 自建数据到上云环境 2.6 mysql数据到其他国产数据库 三、数据库物理迁移实施方案 3.1 数据库物理迁移概述 3.1.1 物理迁移适用场景 3.1.2 物理…

TCP三次握手

TCP三次握手 文章目录 TCP三次握手1. TCP三次握手过程和状态变迁1. 准备工作2. 进行连接 2. 能把三次握手改为两次握手吗&#xff1f;3. 改为两次握手会出现什么后果&#xff1f;4. 改为四次握手行不行&#xff1f;5. TCP第三次握手失败了怎么办&#xff1f;6. 三次握手是否可以…

TCP四次挥手

TCP四次挥手详解 文章目录 TCP四次挥手详解1. TCP四次挥手过程和状态变迁2. 为什么挥手需要四次&#xff1f;3. 为什么中间的ACK和FIN不可以像三次握手那样合为一个报文段呢&#xff1f;4. 为什么TIME_WAIT等待的时间是2MSL&#xff1f;5. 等待2MSL的意义5.1 保证客户端最后发送…

Linux网络——Shell编程之数组

Linux网络——Shell编程之数组 一、概念二、数组的定义三、Shell数组操作1. 获取数组的所有元素的列表2. 获取数组的所有元素下标3.取数组的元素个数4. 获取数组的某个元素的值5.删除数组某个元素6.删除数组7.数组切片8.数组字符替换9.数组追加元素 四、数组在函数的传参 一、概…

天猫数据分析:2023年Q1天猫净水器品牌销售TOP10排行榜

水质的好坏更是与人们的身体健康密切相关。随着社会经济的发展&#xff0c;居民生活水平提升&#xff0c;人们对饮用水质量、安全性的要求也不断提高&#xff0c;净水器也因此逐渐成为现代生活的必需品。 根据鲸参谋电商数据显示&#xff0c;2023年Q1在天猫平台上&#xff0c;净…

3. SQL底层执行原理详解

一条SQL在MySQL中是如何执行的 1. MySQL的内部组件结构1.1 Server层1.2 Store层 2. 连接器3. 分析器4. 优化器5. 执行器6. bin-log归档 本文是按照自己的理解进行笔记总结&#xff0c;如有不正确的地方&#xff0c;还望大佬多多指点纠正&#xff0c;勿喷。 1. MySQL的内部组件结…

MVC分部视图的使用:Html.Partial/RenderPartial,Html.Action/RenderAction,RenderPage

ASP.NET MVC 里的部分视图&#xff0c;相当于 Web Form 里的 User Control。我们的页面往往会有许多重用的地方&#xff0c;可以进行封装重用。 使用部分视图有以下优点&#xff1a; 1. 可以简写代码。 2. 页面代码更加清晰、更好维护。 在视图里有多种方法可以 加载部分视图&a…

硬盘数据突然消失怎么回事?硬盘数据突然消失怎么找回

硬盘上的数据对每个人都至关重要&#xff0c;它可能是我们的珍贵回忆&#xff0c;多年学习的总结&#xff0c;或者一些不可告人的秘密。而硬盘中的数据可能会在不知情的情况下消失或被删除&#xff0c;这种情况对我们来说十分痛苦和困扰。然而&#xff0c;我们不必担心&#xf…

如何用100天彻底学会Python?

Python 是一门功能强大、易于学习且历史悠久的编程语言。如果你希望在短时间内彻底学会 Python&#xff0c;需要制定一个全面的学习计划&#xff0c;并进行刻意的练习和实践。 以下是一份建议的学习计划&#xff0c;帮助你在 100 天内掌握 Python 技能。 第 1-10 天&#xff…

JavaScript class和继承的原理

&#xff08;对于不屈不挠的人来说&#xff0c;没有失败这回事。——俾斯麦&#xff09; class 相关链接 MDN链接 有关类的详细描述 关于构造函数&#xff0c;原型和原型链的说明 类的概述 类是用于创建对象的模板。他们用代码封装数据以处理该数据。JS 中的类建立在原型上…

【Queue新技法】用双数组实现一个队列 C++

目录 1 常规的队列构建2 加入一些限制2-1形式化说明2-2 优化&#xff1a;平衡队列 附录0 双数组或双链表实现队列1 单链表与循环缓冲区实现队列3 参考资料 1 常规的队列构建 到火车站办理退票&#xff0c;排队的人构成队列。注意到有两个关键动作&#xff1a; 入队&#xff0c…

C++类和对象(上)

目录 一、类 1.1 类的引入 1.2 类的定义 1.3 类的访问限定符及封装 1.3.1 类的访问限定符 1.3.2 封装 1.4 类定义方式 1.4.1 声明和定义都放在类体里 1.4.2 类可以声明和定义分离 1.5 类的作用域 1.6 类的实例化 1.6.1 定义 1.6.2 计算类对象的大小 二、this指针…

华为OD机试真题 Java 实现【猜字谜】【2023Q2】

一、题目描述 小王设计了一人简单的清字谈游戏&#xff0c;游戏的迷面是一人错误的单词&#xff0c;比如nesw&#xff0c;玩家需要猜出谈底库中正确的单词。猜中的要求如 对于某个谜面和谜底单词&#xff0c;满足下面任一条件都表示猜中&#xff1a; 变换顺序以后一样的&…

【MySQL】索引

之前的select所采用的方式是遍历数据表进行查找,这种方式效率是比较低的,尤其是数据表汇总数据量比较大的时候,于是便有了索引,MySQL中的索引的作用就是为了快速获取数据 文章目录 1.索引简介2.索引的数据结构2.1 B-Tree2.2 Hash索引 3.索引的分类4.索引的语法5.SQL性能分析6.…
最新文章