Java学习Day13------Properties、多线程

属性集Properties

(1)概述
  是一个Map集合,可以用于存放键值对。最为主要的功能是可以与 IO 结合使用。
(2)常用方法

方法API备注
void store(输出流对象,描述信息)void store(OutputStream out,Stringcomments)void store(Writer writer,Stringcomments)存值。集合存到文件
void load(输入流对象)void load(InputStreaminStream)void load(Readerreader)取值。文件读取到集合

(3)案例

//采用Properties 与IO结合的方法
public class Test04 {
    public static void main(String[] args) throws IOException {
        cun();
        qu();
    }
    
    public static void cun() throws IOException {
        String path = "JavaSEDay13\\dir\\属性集3.properties";
        //存放数据
        Properties pp = new Properties();
        pp.setProperty("username", "张三");
        pp.setProperty("password", "123");
        //调用方法
        FileWriter fw = new FileWriter(path);
        pp.store(fw, "我第一次的修改");
        fw.close();
    }
    public static void qu() throws IOException {
        String path = "JavaSEDay13\\dir\\属性集3.properties";
        //获取数据
        Properties pp = new Properties();
        FileReader fr = new FileReader(path);
        pp.load(fr);
        fr.close();
        //展示结果
        // pp.forEach((key, value) -> System.out.println(key + ":" + value));
        Set<String> strings = prop.stringPropertyNames();
        for (String key : strings) {
            String value = prop.getProperty(key);
            System.out.println(key + ":" + value);
        }
    }
}

多线程

(1)并发和并行
  并行:在同一时刻,有多个指令在多个CPU上同时执行
  并发:在同一时刻,有多个指令在单个CPU上交替执行
(2)进程
  a) 概述:正在运行的软件
  b) 特性:
    独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
    动态性:进程的实质是程序的一次执行过程,进程是动态产生的…
    并发性:…
(3)线程
  a) 概述:是进程中单个顺序控制流,是一条执行路径

多线程实现方式

(1)继承Thread类

//多线程的实现方式一:继承Thread类
public class XianCheng extends Thread {
    //重写 run 方法
    @Override
    public void run() {
        //循环执行任务 1-20
        for (int i = 1; i < 21; i++) {
            //获取到当前执行线程的名称
            String name = Thread.currentThread().getName();
            System.out.println(name + "正在执行:" + i);
        }
    }
}

//测试类
public class Test {
    public static void main(String[] args) {
        //创建对象
        XianCheng xc1 = new XianCheng();
        XianCheng xc2 = new XianCheng();
        //设置线程的名称
        xc1.setName("双神");
        xc2.setName("川神");
        //开启线程
        xc1.start();
        xc2.start();
    }
}

在这里插入图片描述

(2)实现Runnable接口

//多线程的实现方式二:实现 Runnable 接口
public class XianCheng implements Runnable{
    @Override
    public void run() {
        //循环执行任务 1-20
        for (int i = 1; i < 21; i++) {
            //获取到当前执行线程的名称
            String name = Thread.currentThread().getName();
            System.out.println(name + "正在执行:" + i);
        }
    }
}

//测试类
public class Test {
    public static void main(String[] args) {
        // (1). 创建多线程实现类的对象
        XianCheng xc1 = new XianCheng();
        XianCheng xc2 = new XianCheng();
        // (2). 将多线程实现类的对象,作为参数传递个线程类
        Thread t1 = new Thread(xc1);
        Thread t2 = new Thread(xc2);
        // (3). 设置线程的名称
        t1.setName("111");
        t2.setName("222");
        // (4). 开启线程
        t1.start();
        t2.start();
    }
}

(3)实现Callable接口

//线程类,多线程实现方式三:实现Callable接口
public class XianCheng implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 21; i++) {
            //获取到当前执行线程的名称
            String name = Thread.currentThread().getName();
            System.out.println(name+"正在执行:"+i);
        }
        //返回结果
        return "老铁666加油!~~";
    }
}
//测试类
public class Test {
    public static void main(String[] args) throws Exception {
        //第一个结果是第二个的参数,第二个的结果是第三个的参数
        //当第三个执行完毕之后,拿到第二个的返回值
        //-------------
        // (1). 创建线程类的对象
        XianCheng xc = new XianCheng();
        // (2). 创建 FutureTask 的对象
        FutureTask<String> fut = new FutureTask<>(xc);
        // (3). 将上述 Fut的对象作为参数传递给线程
        Thread tt = new Thread(fut);
        // (4). 设置名称, 开启线程
        tt.setName("老铁");
        tt.start();
        // (5). 获取返回值
        String fanHuiZhi = fut.get();
        System.out.println("fanHuiZhi = " + fanHuiZhi);
    }
}

继承 Thread 类 、实现 Runnable 接口和实现Callable 接口的对比

(1)有返回值的时候(线程执行完毕之后,有结果的情况)采用Callable 接口去实现多线程
(2)如果没有返回值的时候(线程执行完毕之后,没有结果的情况),采用继承Thread 类, 或者是实现 Runnable接口(Runnable接口使用较多)
(3)继承 Thread 类。代码写法简单,但是缺点是不能继续继承其他的类
(4)实现 Runnable 接口。 代码写法复杂, 但是可以继续继承其他类,实现其他接口。
(5)后期一般会选择 实现 Runnable 接口的方式。原因: 可以继承其他类,实现其他接口,还可以采用 Lambda 表达式, 实现数据和线程的分离。
在这里插入图片描述

线程安全问题(购票案例)

在这里插入图片描述
(1)图中就出现了票数少于0的情况,这就是线程访问的安全问题(在多个线程共享一份数据,同时出现了数据的修改的时候,如果不进行处理就会出现线程安全问题)
(2)解决方案
  a) 同步代码块

//线程类: 采用多线程的第二种实现方式【同步代码块解决】
public class TicketThread implements Runnable{
    //定义总票数
    private int ticketNum = 100;
    @Override
    public void run() {
        //死循环不断的去卖票
        while(true){
            synchronized (this) {  //锁对象是 this  Ctrl+Alt+T
                //当总票数小于等于0的时候结束
                if (ticketNum<=0){
                    break;
                }else{
                    // --------
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // --------
                    ticketNum--;
                    String name = Thread.currentThread().getName();
                    System.out.println(name+"已经卖出了票,剩余:"+ticketNum);
                }
            }
        }
    }
}

  b) 同步方法

//线程类: 采用多线程的第二种实现方式【同步方法解决】
public class TicketThread implements Runnable {
    //定义总票数
    private int ticketNum = 100;
    @Override
    public void run() {
        //死循环不断的去卖票   抽取方法的快捷键 Ctrl+Alt+M
        while (true) {
            if (sell()) break;
        }
    }
    public synchronized boolean sell() {
        //当总票数小于等于0的时候结束
        if (ticketNum <= 0) {
            return true;
        } else {
            // --------
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // --------
            ticketNum--;
            String name = Thread.currentThread().getName();
            System.out.println(name + "已经卖出了票,剩余:" + ticketNum);
        }
        return false;
    }
}

  c) lock锁(需要采用 finally 代码块, 在 finally 代码块当中去解锁。保证一定能够解锁)

//线程类: 采用多线程的第二种实现方式【Lock锁的实现方式】
public class TicketThread implements Runnable {
    //定义总票数
    private int ticketNum = 100;
    //[1]创建锁对象
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        //死循环不断的去卖票
        while (true) {
            try {
                //[2]上锁
                lock.lock();
                //当总票数小于等于0的时候结束
                if (ticketNum <= 0) {
                    break;
                } else {
                    // --------
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // --------
                    ticketNum--;
                    String name = Thread.currentThread().getName();
                    System.out.println(name + "已经卖出了票,剩余:" + ticketNum);
                }
            } finally {
                //[3]释放锁
                lock.unlock();
            }
        }
    }
}

死锁问题

(1)当 多个线程中出现锁的嵌套的时候就会出现死锁现象
(2)案例

//演示死锁的案例(你中有我,我中有你)
public class Test {
    public static void main(String[] args) {
        //准备两把锁
        Object lockA = new Object();
        Object lockB = new Object();
        //new Thread(()->{}).start();   Lambda就是run()方法
        //开启线程1
        new Thread(()->{
            while(true){
                synchronized (lockA){
                    synchronized (lockB){
                        System.out.println("线程111,正在执行 A 中有 B");
                    }
                }
            }
        }).start();
        //开启线程2
        new Thread(()->{
            while(true){
                synchronized (lockB){
                    synchronized (lockA){
                        System.out.println("线程222,正在执行 B 中有 A");
                    }
                }
            }
        }).start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值