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

配置文件

        介绍 

        配置文件 

  • 在企业开发过程中,我们习惯把一些需要灵活配置的数据放在一些文本文件中而不是在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其他方法说明

 

  • 16
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值