【Day10-配置文件日志多线程】

news2024/11/15 7:19:18

配置文件

        介绍 

        配置文件 

  • 在企业开发过程中,我们习惯把一些需要灵活配置的数据放在一些文本文件中而不是在Java代码写死
  • 我们把这种存放程序配置信息的文件统称为配置文件

 

          Properties

  • 是一个Map集合(键值对集合),但是我们一般不会当集合使用。
  • 核心作用:Properties是用来代表属性文件的,通过Properties可以读写属性文件里的内容。

使用Properties读取属性文件里的键值对数据 

 使用Properties把键值对数据写出到属性文件里去

/*
properties配置文件
特点:
    1、都只能是键值对
    2、键不能重复
    3、文件后缀一般是.properties结尾的

Properties
    这是一个Map集合(键值对集合),但是我们一般不会当集合使用
    主要用来代表属性文件,通过Properties可以读写属性文件里的内容

读取
    public Properties()  创建Properties集合对象

    public void load(InputStream is/Reader reader)  通过输入流读取文件中的键值对数据
    public String getProperty(String key) 	根据键获取值(其实就是get方法的效果)
    public Set<String> stringPropertyNames()	获取全部键的集合(其实就是ketSet方法的效果)

写出
    public Properties()  创建Properties集合对象

    public Object setProperty(String key, String value) 	保存键值对数据到Properties对象中去。
    public void store(OutputStream os/Writer writer, String comments)	把键值对数据,通过输出流写出到属性文件里去
*/
public class Demo1 {
    public static void main(String[] args) throws IOException {
        //1. 创建一个配置文件对象
        Properties prop = new Properties();
        prop.load(new FileReader("day10-code/user.properties"));
        //2. 读取
        String admin = prop.getProperty("admin");
        System.out.println(admin);
        Set<String> keys = prop.stringPropertyNames();
        for (String key : keys) {
            String value = prop.getProperty(key);
            System.out.println(key + "--" + value);
        }
        //3. 写出
        Properties prop2 = new Properties();
        prop2.setProperty("SSS", "888");
        prop2.setProperty("AAA", "999");
        prop2.store(new FileWriter("day10-code/user2.properties"),"abc");
    }
}

        1、Properties的作用?具体如何使用?

                可以加载属性文件中的数据到Properties对象中来

                void load​(Reader reader)

                public String getProperty(String key)   根据键获取值

                可以存储Properties属性集的键值对数据到属性文件中去

                void store​(Writer writer, String comments)  设置键值

                public Object setProperty(String key, String value)

        XML 

        认识XML

 

        XML
  • 全称Extensible Markup Language 可扩展标记语言
  • 本质是一种数据的格式,可以用来存储复杂的数据结构,和数据关系。

        XML的特点
  • XML中的“<标签名> 称为一个标签或一个元素,一般是成对出现的。
  • XML中的标签名可以自己定义(可扩展),但必须要正确的嵌套。
  • XML中只能有一个根标签。
  • XML中的标签可以有属性。
  • 如果一个文件中放置的是XML格式的数据,这个文件就是XML文件,后缀一般要写成.xml
        XML的语法规则
  • XML文件的后缀名为:xml文档声明必须是第一行

 

  • XML中可以定义注释信息:<!–- 注释内容 -->快捷键是Ctrl+shift+/
  • XML中书写”<”、“&”等,可能会出现冲突,导致报错,此时可以用如下特殊字符替代。

  • XML中可以写一个叫CDATA的数据区: <![CDATA[   …内容…  ]]>,里面的内容可以随便写。直接输入CD,就会有提示 
<?xml version="1.0" encoding="UTF-8" ?>
<!--这是注释内容-->
<users>
    <user id="1">
        <name>张无忌</name>
        <password>minmin</password>
        <address>光明顶</address>
        <gender>男</gender>
    </user>
    <user id="2">
        <name>敏敏</name>
        <password><![CDATA[
            < > &
        ]]></password>
        <address>光明顶</address>
        <gender>女</gender>
    </user>
</users>
        XML的作用和应用场景
  • 本质是一种数据格式,可以存储复杂的数据结构,和数据关系。
  • 应用场景:经常用来做为系统的配置文件;或者作为一种特殊的数据结构,在网络中进行传输

        1、XML是什么?  有啥作用?

                XML的是一种可扩展的标记语言。

                作用:1)作为软件的配置文件   2)用于进行存储数据和传输数据

        2、XML的组成格式要求是什么样的?

                文件后缀一般是是xml,文档声明必须是第一行

                必须存在一个根标签,有且只能有一个

                XML文件中可以定义注释信息:<!–- 注释内容 -->

                标签必须成对出现,有开始,有结束标签: <name></name>

                必须能够正确的嵌套

         读取XML

         解析XML文件
  • 使用程序读取XML文件中的数据
         DOM4J解析XML文件的思想:文档对象模型
         Dom4j解析XML-得到Document对象

SAXReaderDom4j提供的解析器,可以认为是代表整个Dom4j框架 

构造器/方法

说明

public SAXReader()

构建Dom4J的解析器对象

public Document read(String path)

XML文件读成Document对象

 Document

方法名

说明

Element getRootElement()

获得根元素对象

Element提供的方法 

方法名

说明

public String getName()

得到元素名字

public List<Element> elements()

得到当前元素下所有子元素

public List<Element> elements(String name)

得到当前元素下指定名字的子元素返回集合

public Element element(String name)

得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个

public String  attributeValue(String name)

通过属性名直接得到属性值

public String elementText(子元素名)

得到指定名称的子元素的文本

public String getText()

得到文本

         案例:

/*
需求: 解析b-2.xml,将内容封装到一个List<User对象的集合>

XML解析
    DOM解析思想
        DOM (document Object Model)文档对象模型
        将文档的各个组成部分看做是对应的对象
        首先会将xml文件全部加载到内存,在内存中形成一个树状结构,在获取对应的值
        DOM解析思想就是一层一层的进入,一层一层的解析

    对象分类
        Document:整个xml文档对象
        Element: 标签对象
        Attribute:属性对象
        Text标签体:文本对象

    DOM4J解析XML准备工作
        1、将dom4j的jar包加入到项目中
        2、创建DOM4]解析器对象SAXReader,获取Document文档对象,获取根标签对象
        3、从根标签对象开始往下层层解析


    详细API
        SAXReader:Dom4j提供的解析器,可以认为是代表整个Dom4j框架
            public SAXReader() 	构建Dom4J的解析器对象
            public Document read(String path)	把XML文件读成Document对象
        Element getRootElement() 	获得根元素对象
            public String getName()	得到元素名字
            public List<Element> elements()	得到当前元素下所有子元素
            public List<Element> elements(String name)	得到当前元素下指定名字的子元素返回集合
            public Element element(String name)	得到当前元素下指定名字的子元素,如果有很多名字相同的返回第一个
            public String  attributeValue(String name)	通过属性名直接得到属性值
            public String elementText(子元素名)	得到指定名称的子元素的文本
            public String getText()	得到文本

 */
public class Demo2 {
    public static void main(String[] args) throws Exception {
        ArrayList<User> users = new ArrayList<>();
//        1、将dom4j的jar包加入到项目中
//        2、创建DOM4]解析器对象SAXReader,获取Document文档对象,获取根标签对象
        SAXReader saxReader = new SAXReader();
        //读取xml文件
        Document document = saxReader.read(new FileReader("day10-code/b-2.xml"));
//        3、从根标签对象开始往下层层解析
        Element rootElement = document.getRootElement();
        //获取根标签的名字
        String rootName = rootElement.getName();
        System.out.println("name=" + rootName);
        //获取根标签下的所有子标签
        List<Element> elements = rootElement.elements();
        System.out.println(elements.size());
        //遍历标签的集合
        for (Element element : elements) {
            String name = element.getName();
            String id = element.attributeValue("id");
            System.out.println("子标签名字:" + name + id);
            List<Element> elements1 = element.elements();
            System.out.println(elements1.size());
            String userName = element.element("name").getText();
            System.out.println("name" + userName);
            String password = element.element("password").getText();
            System.out.println("password" + password);
            String address = element.element("address").getText();
            System.out.println("address" + address);
            String gender = element.element("gender").getText();
            System.out.println("gender" + gender);
            User user = new User(userName, password, address, gender);
            users.add(user);
        }
        for (User user : users) {
            System.out.println(user);
        }
    }
}
class User{
    private String name;
    private String password;
    private String address;
    private String gender;

    public User() {
    }

    public User(String name, String password, String address, String gender) {
        this.name = name;
        this.password = password;
        this.address = address;
        this.gender = gender;
    }


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }


    public String getPassword() {
        return password;
    }


    public void setPassword(String password) {
        this.password = password;
    }


    public String getAddress() {
        return address;
    }


    public void setAddress(String address) {
        this.address = address;
    }


    public String getGender() {
        return gender;
    }


    public void setGender(String gender) {
        this.gender = gender;
    }

    public String toString() {
        return "User{name = " + name + ", password = " + password + ", address = " + address + ", gender = " + gender + "}";
    }
}
<?xml version="1.0" encoding="UTF-8" ?>
<users>
    <user id="1">
        <name>张无忌</name>
        <password>minmin</password>
        <address>光明顶</address>
        <gender>男</gender>
    </user>
    <user id="2">
        <name>敏敏</name>
        <password>wuji</password>
        <address>光明顶</address>
        <gender>女</gender>
    </user>
</users>

         XML约束

         什么是约束XML文件的书写?
  • 就是限制XML文件只能按照某种格式进行书写。 

         约束文档

  • 专门用来限制xml书写格式的文档,比如:限制标签、属性应该怎么写。 

        约束文档的分类

  • DTD文档
  • Schema文档

        XML文档约束-DTD的使用(了解) 

需求:利用DTD约束文档,约束一个XML文件的编写。

①:编写DTD约束文档,后缀必须是.dtd

②:在需要编写的XML文件中导入该DTD约束文档

③:然后XML文件,就必须按照DTD约束文档指定的格式进行编写,否则报错!

        XML文档约束-schema的使用(了解) 

需求:利用schema文档约束,约束一个XML文件的编写。

①:编写schema约束文档,后缀必须是.xsd,具体的形式到代码中观看。

②:在需要编写的XML文件中导入该schema约束文档

③:按照约束内容编写XML文件的标签。

/*
案例需求: 将如下数据写入到b-3.xml中
    <?xml version="1.0"encoding="UTF-8"?>
    <book>
        <name>Java从入门到放弃</name>
        <author>黑马-小明老师</author>
        <price>89.5</price>
    </book>

如何从程序中写数据到xml文件中
    不建议用DOM4J将数据写入到xml文件中
    推荐在java代码中,将数拼接成xml格式,用IO流写出去
*/
public class Demo3 {
    public static void main(String[] args) throws Exception {
        //1.拼接xml内容的字符串
        //使用可变字符串对象去拼接
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\"encoding=\"UTF-8\"?>\r\n");
        sb.append("<book>\r\n");
        sb.append("<name>Java从入门到放弃</name>\r\n");
        sb.append("<author>黑马-小明老师</author>\r\n");
        sb.append("<price>89.5</price>\r\n");
        sb.append("</book>\r\n");
        //拼接完成后返回字符串
        String xmlStr = sb.toString();
        //2.IO流写到文件
        try (
                FileWriter writer = new FileWriter("day10-code/b-3.xml")
        ){
            //使用Writer, FileWriter
            //把拼接好的字符串写到文件中
            writer.write(xmlStr);
            //关闭流
//            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 日志文件

         概述

 

        日志技术 

  • 可以将系统执行的信息,方便的记录到指定的位置(控制台、文件中、数据库中)。
  • 可以随时以开关的形式控制日志的启停,无需侵入到源代码中去进行修改。

         日志技术的体系结构

  • 日志接口:设计日志框架的一套标准,日志框架需要实现这些接口。
  • 日志框架:牛人或者第三方公司已经做好的实现代码,后来者直接可以拿去使用。
  • 注意1因为对Commons Logging接口不满意,有人就搞了SLF4J;因为对Log4j的性能不满意,有人就搞了Logback
  • 注意2Logback是基于slf4j的日志规范实现的框架。

        1、什么是日志?

                用来记录程序运行过程中的信息,并可以进行永久存储。

        2、常见的日志实现框架有哪些?

                Log4J、Logback(我们重点学习的,其他的都大同小异)

                Logback是基于slf4j日志接口实现的日志框架

        3、使用Logback至少需要使用哪几个模块?

                slf4j-api:日志接口

                logback-core:基础模块

                logback-classic:功能模块,它完整实现了slf4j API 

        Logback快速入门 

需求

使用 Logback 日志框架,纪录系统的运行信息。

实现步骤

①:导入Logback框架到项目中去。

②:Logback框架的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)。

③:创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录系统的日志信息 。

/*
需求
    使用Logback日志框架,纪录系统的运行信息。
实现步骤
    1. 导入Logback框架到项目中去。
    2. 将Logback框架的核心配置文件logback.xml直接拷贝到src目录下(必须是src下)。
    4. 创建Logback框架提供的Logger对象,然后用Logger对象调用其提供的方法就可以记录系统的日志信息。
        public static final Logger LOGGER = LoggerFactory.getLogger("当前类类名");
    5. 打印日志
        LOGGER.info("日志信息")
        LOGGER.debug("日志信息")
        LOGGER.error("日志信息")
*/
public class Demo1 {
    public static final Logger LOGGER = LoggerFactory.getLogger("Demo1");
    public static void main(String[] args) {
        LOGGER.info("你喜欢跳舞吗?");
        div(5,2);
        div(5,0);
    }

    public static int div(int a, int b) {
        int c = 0;
        try {
            LOGGER.debug("方法执行了,a={},b={}", a,b);
             c = a / b;

        } catch (Exception e) {
            LOGGER.error("{}/{}出错了", a, b);
            e.printStackTrace();
        }
        return c;
    }
}

        核心配置文件logback.xml

对Logback日志框架进行控制的。 

        日志的输出位置、输出格式的设置 

通常可以设置2个输出日志的位置:一个是控制台、一个是系统文件中 

         Logback设置日志级别

        什么是日志级别? 

日志级别指的是日志信息的类型,日志都会分级别,常见的日志级别如下(优先级依次升高): 

日志级别

说明

trace

追踪,指明程序运行轨迹

debug

调试,实际应用中一般将其作为最低级别,而 trace 则很少使用

info

输出重要的运行信息,数据连接、网络连接、IO操作等等,使用较多

warn

警告信息,可能会发生问题,使用较多

error

错误信息,  使用较多

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--
        CONSOLE :表示当前的日志信息是可以输出到控制台的。
    -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--输出流对象 默认 System.out 改为 System.err-->
        <target>System.out</target>
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
                %msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern>
        </encoder>
    </appender>

    <!-- File是输出的方向通向文件的 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!--日志输出路径-->
        <file>C:/log/itheima-data.log</file>
        <!--指定日志文件拆分和压缩规则-->
        <rollingPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--通过指定压缩文件名称,来确定分割文件方式-->
            <fileNamePattern>C:/log/itheima-data-%i-%d{yyyy-MM-dd}-.log.gz</fileNamePattern>
            <!--文件拆分大小-->
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
    </appender>

    <!--
        1、控制日志的输出情况:如,开启日志,取消日志
    -->
    <root level="ALL">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE" />
    </root>
</configuration>

         为什么要学习日志级别? 

 

只有日志的级别是大于或等于核心配置文件配置的日志级别才会被记录,否则不记录 

        1、设置日志输出级别的作用是什么?

                用于控制系统中哪些日志级别是可以输出的

        2、Logback的日志级别是什么样的? 

                ALL  和 OFF分别是打开全部日志和关闭全部日志

                级别程度依次是:TRACE< DEBUG< INFO<WARN<ERROR

                默认级别是debug(忽略大小写),只输出当前级别及高于该级别的日志

 多线程

        什么是线程? 

  • 线程简单的说,就是计算机在做一件事
  • 单线程:在计算机中同一时间只能做一件事
  • 多线程:在计算机中同一时间可以做多件事

         多线程在程序中的应用

         线程的创建方式

         继承Thread类

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

  1. 定义一个子类继承线程类java.lang.Thread,重写run()方法
  2. 创建类的对象
  3. 调用子对象的start()方法启动线程(底层会自动去执行run方法 

        方式一优缺点 

  • 优点:编码简单
  • 缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。

        多线程的注意事项

1、启动线程必须是调用start方法,不是调用run方法。

  • 直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
  • 只有调用start方法才是启动一个新的线程执行。

2、不要把主线程任务放在启动子线程之前。 

  • 这样主线程一直是先跑完的,相当于是一个单线程的效果了。 
/*
多线程
    让程序同时做多件事

多线程的创建方式一:继承Thread类
    1. 定义一个子类继承线程类java.lang.Thread,重写run()方法
    2. 创建子类的对象
    3. 调用子类对象的start()方法启动线程(底层会自动去执行run方法)

优缺点
    优点:编码简单
    缺点:线程类已经继承Thread,无法继承其他类,不利于功能的扩展。

注意事项
    1、启动线程必须是调用start方法,不是调用run方法。
    2、直接调用run方法会当成普通方法执行,只有调用start方法才是启动一个新的线程执行。
    3、不要将主线任务放在start方法之前,这样主线程一直是先跑完的,相当于是一个单线程的效果了。

扩展
    对于单核cpu来讲, 多线程是一种假象
*/
public class Demo1 {
    public static final Logger LOGGER = LoggerFactory.getLogger("Demo1");
    public static void main(String[] args) {
        //需求:创建两个线程,分别用于打印10个A和10个B,最后观察下输出顺序
        AThread aThread = new AThread();
        BThread bThread = new BThread();
        aThread.start();
        bThread.start();

        for (int i = 0; i <20; i++) {
            LOGGER.debug("main-" + i);
        }
    }
}
class AThread extends Thread {
    public static final Logger LOGGER = LoggerFactory.getLogger("AThread");
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            LOGGER.info("A-" + i);
        }
    }
}
class BThread extends Thread {
    public static final Logger LOGGER = LoggerFactory.getLogger("BThread");
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            LOGGER.info("B-" + i);
        }
    }
}

        1、什么是多线程?

                同时做多件事

        2、线程创建方式一的具体步骤是?

  • 继承Thread类,重写run方法
  • 创建线程对象
  • 调用start()方法启动

        3、线程的第一种创建方式有啥优缺点?

  • 优点:编码简单
  • 缺点:存在单继承的局限性,线程类继承Thread后,不能继承其他类,不便于扩展

          实现Runnable接口

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

定义一个线程任务类实现 Runnable 接口,重写 run() 方法
创建任务类对象
把任务类对象交给 Thread 处理
调用线程对象的 start() 方法启动线程

Thread类提供的构造器

说明

public Thread(Runnable target)

封装Runnable对象成为线程对象

         方式二的优缺点

  • 优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
  • 缺点:需要多一个Runnable对象。
/*
多线程的创建方式二:实现Runnable接口
    1. 定义一个线程任务类实现Runnable接口,重写run()方法
    2. 创建任务类对象
    3. 把任务类对象交给Thread处理
        public Thread(Runnable target)
    4. 调用线程对象的start()方法启动线程

优缺点
    优点:任务类只是实现接口,可以继续继承其他类、实现其他接口,扩展性强。
    缺点:需要多一个Runnable对象。
*/
public class Demo1 {

    public static void main(String[] args) {
        //需求:创建两个线程,分别用于打印10个A和10个B,最后观察下输出顺序
        AThread aThread = new AThread();
        BThread bThread = new BThread();

        Thread t1 = new Thread(aThread);
        Thread t2 = new Thread(bThread);
        t1.setName("t1-a");
        t2.setName("t2-b");
        t1.start();
        t2.start();

    }
}

class AThread implements Runnable{
    public static final Logger LOGGER = LoggerFactory.getLogger("AThread");
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            LOGGER.debug("A-" + i);
        }
    }
}
class BThread implements Runnable{
    public static final Logger LOGGER = LoggerFactory.getLogger("BThread");
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            LOGGER.debug("B-" + i);
        }
    }
}

        1、线程创建方式二是如何创建线程的?

                定义一个线程任务类实现Runnable接口,重写run()方法

                创建任务类对象

                把任务对象交给Thread线程对象处理

                调用线程对象的start()方法启动线程

        2、方式二的优缺点是啥?

                优点:线程任务类只是实现了Runnale接口,可以继续继承和实现

                缺点:如果线程有执行结果是不能直接返回的

          实现Callable接口 

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

创建任务对象
  • 定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。
  • Callable类型的对象封装成FutureTask(线程任务对象)。
把线程任务对象交给 Thread 对象。
调用 Thread 对象的 start 方法启动线程。
线程执行完毕后、通过 FutureTask 对象的的 get 方法去获取线程任务执行的结果。

         FutureTaskAPI

FutureTask提供的构造器

说明

public FutureTask<>(Callable call)

Callable对象封装成FutureTask对象。

FutureTask提供的方法

说明

public V get() throws Exception

获取线程执行call方法返回的结果。

        线程创建方式三的优缺点 

  • 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果。
  • 缺点:编码复杂一点。
/*
多线程的创建方式三:实现Callable接口
    1. 创建任务对象
        定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据
        把Callable类型的对象封装成FutureTask(线程任务对象)
            public FutureTask<>(Callable call)	把Callable对象封装成FutureTask对象
            public V get() throws Exception	获取线程执行call方法返回的结果
    2. 把线程任务对象交给Thread对象。
    3. 调用Thread对象的start方法启动线程。
    4. 线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果

优缺点
    优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强;可以在线程执行完毕后去获取线程执行的结果
    缺点:编码复杂一点。
*/
public class Demo1 {

    public static void main(String[] args) throws Exception {
        //需求:启动两个子线程,分别计算100之内的奇数的和和偶数的和,然后在主线程中再做个汇总,得到总和
        //创建callable的对象
        OddThread oddThread = new OddThread();
        EvenThread evenThread = new EvenThread();
        //创建FutureTask对象
        FutureTask<Integer> oddFutureTask = new FutureTask<>(oddThread);
        FutureTask<Integer> evenFutureTask = new FutureTask<>(evenThread);
        //创建线程对象
        Thread oddT = new Thread(oddFutureTask, "奇数线程");
        Thread evenT = new Thread(evenFutureTask, "偶数线程");
        //调用线程的对象
        oddT.start();
        evenT.start();
        //获取线程的结果
        Integer oddSum = oddFutureTask.get();
        Integer evenSum = evenFutureTask.get();

        int sum = oddSum + evenSum;
        System.out.println(sum);
    }
}

//计算100以内的奇数和,并返回
class OddThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i+=2) {
            sum += i;
        }
        return sum;
    }
}
//计算100以内的偶数和,并返回
class EvenThread implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i <= 100; i+=2) {
            sum += i;
        }
        return sum;
    }
}

请对对比说一下三种线程的创建方式,和不同点?

方式

优点

缺点

继承Thread

编程比较简单,可以直接使用Thread类中的方法

扩展性较差,不能再继承其他的类,不能返回线程执行的结果

实现Runnable接口

扩展性强,实现该接口的同时还可以继承其他的类。

编程相对复杂,不能返回线程执行的结果

实现Callable接口

扩展性强,实现该接口的同时还可以继承其他的类。可以得到线程执行的结果

编程相对复杂

          Thread类的方法

        Thread线程操作相关的方法 

        Thread线程获取线程、设置线程、拿到当前线程对象

         Thread线程休眠、线程join

          Thread其他方法说明

 

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

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

相关文章

推荐系统的基础_协同过滤(CF)

协同过滤&#xff08;Collaborative Filtering&#xff09;是一种推荐系统算法&#xff0c;它通过分析用户之间的相似性或者物品之间的相似性来预测用户可能感兴趣的物品。协同过滤算法主要有两种类型&#xff1a; 1. 用户基协同过滤&#xff08;User-based Collaborative Filt…

OceanMind海睿思“一种业务驱动数据治理的方法和系统”获国家发明专利!

近日&#xff0c;中新赛克海睿思最新技术&#xff1a;一种业务驱动数据治理的方法和系统&#xff08;专利号ZL 202410567107.8&#xff09;&#xff0c;获得国家知识产权局的正式授权&#xff0c;并取得专利证书。 当前&#xff0c;现有的数据治理方法论和平台工具主要聚焦于数…

IDEA 常用插件推荐,美观又实用!

1、 TONGYl Lingma - Your Al Coding Assistant. Type less, Code more. 通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码注释生成、代码解释、研发智能问答、异常报错排查等能力&…

JVM 调优篇2 jvm的内存结构以及堆栈参数设置与查看

一 jvm的内存模型 2.1 jvm内存模型概览 二 实操案例 2.1 设置和查看栈大小 1.代码 /*** 演示栈中的异常:StackOverflowError** author shkstart* create 2020 下午 9:08** 设置栈的大小&#xff1a; -Xss (-XX:ThreadStackSize)** -XX:PrintFlagsFinal*/ public class S…

【C++】C++ STL 探索:List使用与背后底层逻辑

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现 本文将通过模拟实现List&#xff0c;从多个角度深入…

第J3周:DenseNet算法实战与解析(pytorch版)

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营]中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊]** &#x1f4cc; 本周任务&#xff1a; ●1.请根据本文 Pytorch 代码&#xff0c;编写出相应的 TensorFlow 代码&#xff08;建议使用…

《黑神话·悟空》背后的佛学义理探析

《黑神话悟空》不仅是一款备受期待的动作冒险游戏&#xff0c;其背后的深厚文化内涵&#xff0c;尤其是佛教义理的体现&#xff0c;更是吸引了不少玩家和佛学爱好者的关注。本文将通过对游戏剧情的解析&#xff0c;结合佛教思想&#xff0c;探讨《黑神话悟空》中所蕴含的哲学智…

冯·诺依曼体系结构

纯硬件的计算机结构应该就是输入设备——CPU——输出设备 冯诺依曼体系结构加入了存储器&#xff08;内存&#xff09; 因为数据是要在计算机体系结构中流动的&#xff0c;流动过程中对数据进行加工处理&#xff0c;数据从一个设备到另流动到另一个设备本质是一种数据拷贝。C…

HDFS常用命令及Python连接HDFS操作

目录 一、HDFS常用命令 二、Python连接HDFS操作 一、HDFS常用命令 HDFS&#xff08;Hadoop Distributed File System&#xff0c;Hadoop分布式文件系统&#xff09;是Hadoop集群中的一部分&#xff0c;用于存储大量数据&#xff0c;并运行在商用硬件集群上。以下是HDFS中常用…

6款好用到离谱的宝藏软件,每一款都超出你的认知

你的电脑里有没有那种&#xff0c;无论重装多少次系统&#xff0c;都要第一时间安装的软件&#xff1f; 请把它的名字打在评论区&#xff01;本期分享6款&#xff0c;免费也能吊打付费的Windows电脑必装软件。 最大程度的增强Windows系统的功能&#xff0c;良心分享&#xff…

一文讲解多种GIS分析功能

GIS行业有很多分析功能&#xff0c;对于刚入行的新手有着足够的吸引力&#xff0c;其实有许多分析功能实现原理大差不差&#xff0c;比如模型压平&#xff0c;基于模型的淹没分析以及模型裁切。本文将以模型裁切为切入口进行介绍其中原理。 首先 &#xff08;立方体剖切示意图…

只需一个类文件,Erupt 可以能完成整个后台管理?这个低代码值得一试

只需一个类文件&#xff0c;Erupt 竟然能搞定整个后台管理&#xff1f;这个低代码值得一试 在纷繁复杂的后端开发世界里&#xff0c;Erupt 就像是一剂强心针&#xff0c;用一个 .class 文件就能实现后台管理功能&#xff0c;简直让人感叹“开发也可以这么简单&#xff01;”本文…

linux进程的概念和pid

进程的概念 进程是参与分配资源&#xff08;cpu&#xff0c;内存&#xff09;得实体&#xff0c;比如打开qq&#xff0c;浏览器就是打开了进程。 进程这么多&#xff0c;如何管理进程呢&#xff1f; 在linux下进程通过PCB&#xff08;task_struct&#xff09;来管理进程 ta…

足浴行业在线预约小程序源码系统+支持拼团功能 带完整的安装代码包以及搭建部署教程

系统概述 在快节奏的现代生活中&#xff0c;人们对健康养生的需求日益增长&#xff0c;足浴行业作为传统养生方式之一&#xff0c;其市场需求也随之不断扩大。为了满足消费者日益增长的便捷性需求&#xff0c;一款集在线预约、拼团优惠于一体的足浴行业小程序源码系统应运而生…

Vue/cli不同环境下打包后js文件没有添加hash值-会导致缓存问题-解决

环境变量 包文件判断是根据NODE_ENV=production,这时会对应打包加上hash值,所以在配置不同环境对应命令的时候,把NODE_ENV=production加上 全局的环境变量需要以VUE_APP_ 开头 process.env.VUE_APP_ENV 会读取不到值 .env 文件配置 NODE_ENV=production 才会按照hash模式去…

利用数据分析提升SEO排名的7种方法

我们都听过“大数据分析”这个词。科技让我们能够清晰地了解我们的活动和内容的表现——向我们提供了关于受众的宝贵信息&#xff0c;甚至可以精确到他们在Google和其他搜索引擎上使用的具体搜索词。 你已经在你的业务中使用数据分析了吗&#xff1f;如果是&#xff0c;你有利…

漏水监测报警摄像机

漏水监测报警摄像机 是一种智能设备&#xff0c;专门用于监测管道或设备的漏水情况&#xff0c;并能在检测到漏水时发出警报&#xff0c;帮助用户及时发现并处理水患。这种摄像机通常配备高清摄像头和敏感的水滴传感器&#xff0c;能够全天候地监测管道周围的情况。 当漏水摄像…

【ARM compiler】生成ELF文件中包含了那些内容

【更多软件使用问题请点击亿道电子官方网站】 文档目标&#xff1a;用于了解ARM compiler生成的ELF文件中存储的内容进行了解 问题场景&#xff1a;ELF文件主要用于通过调试软件对于代码的运行顺序和数据链接等内容进行分析。了解一下ARM compiler生成ELF文件包含那些内容。 软…

蓝牙--关于bta_av_main.cc文件的讲解

简单概要下: BTIF:提供bluedroid对外的接口 BTA:提供各种profile的实现 stack:协议实现与连接管理 上层在建立A2dp connect连接的时候,先调用到btif层的btif_av.cc中函数src_connect_sink,接着调用bta层bta_av_api.cc中函数BTA_AvOpen,经过内部state machine处理,最…

ROPS 自动化快速构造缓冲区溢出ROP链工具

项目地址:https://github.com/MartinxMax/ROPS ROPS 快速自动化构造ROP&#xff08;Return-Oriented Programming&#xff09;链的脚本&#xff0c;用于生成ROP攻击的有效载荷。 Usage $ ./rops.sh $ ./rops.sh /home/ayush/.binary/rop 该脚本将根据提供的二进制文件自动生…