对象流 线程 的创建 以及synchranized reentrantlock 的使用 区别

1.对象流
    ObjectOutputStream
        ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。
        可以使用 ObjectInputStream 读取(重构)对象。

    ObjectInputStream
        ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。 

    序列化(持久化) 和 反序列化 
        持久化:就是将内存中的对象 存储到硬盘上
        反序列化: 就是将硬盘文件中的对象 再读入到内存中
    java对象流 简单来说 就是直接把Object对象 进行 写入 或 读出
    功能:
        方便对象在硬盘上的存储
    例如:
        学生信息
        Student stu = new Student();
        持久化 使用 ObjectOutputStream 将对象的属性信息 存储到指定的硬盘文件上
        反序列化 使用 ObjectInputStream 将硬盘上存储的对象信息 读到内存中 方便使用
    注意:
        想要让对象被序列化 或者 反序列化 必须让该对象所属的类 实现 Serializable接口
        否则 在进行 序列化时出现 NotSerializableException异常
        /*
         * public interface Serializable
         * 类通过实现 java.io.Serializable 接口以启用其序列化功能。
         * 未实现此接口的类将无法使其任何状态序列化或反序列化。
         * */
2.线程
    2.1 线程的概念
        注意:
            线程中的运行结果 如果出现你所不能接受的现实都是可能的
            (多核cpu的影响)
        什么是程序?
            就是一段代码 是一组指令的有序集合
            它本身 没有任何 运行 的含义
        什么是进程?
            进程是程序的一次运行状态
            它对应着 从代码加载 --> 执行 --> 执行完毕的整个过程
            它是有自己的生命周期
            它因创建而产生
            因调度而执行
            因等待资源而处于等待等待状态
            因任务结束而结束
        什么是线程?
            线程就是进程里的一个控制单元 是线程在控制进程
            每个进程里面都包含若干个线程
            一个进程至少由一个线程组成

            线程 是 执行程序的一条路径
            多线程并发 执行 可以提高程序的效率 可以同时完成多项任务
        并发 和 并行:
            并发:
                就是两个任务同时请求运行
                而处理器一次只能接收一个任务 就将两个任务 安排轮流执行
                由于cpu时间片运行时 时间比较快 所以感觉两个程序在同时运行

                操作一台电脑 分别跟两个人聊天
            并行:
                就是两个任务同时运行
                甲任务执行的同时 乙任务也在执行
                双核

                两个手 操作两台电脑 分别跟两个人聊天
        JVM启动的时候 是多线程的
            至少启动了两根线程
                一个是主线程(主线程会调用main方法)
                一个是垃圾回收线程
                
    2.2 线程的创建方式
        继承Thread类
            线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
            /*
             * 发现运行结果每次都不同
             *     因为多个线程都在抢夺cpu的执行权 cpu执行到谁 就运行谁
             *  明确一点 在某一个时刻 只能有一个线程在运行(多核除外)
             *  cpu在做着快速的切换 已达到看上去同时运行的效果
             *  我们可以形象的把线程的运行  视为在互相抢夺cpu的执行权
             *  这也就是多线程的一个特性 随机性 谁抢到 就算谁的 至于执行多长时间 由cpu说了
             *  
             *  run()方法 和 start()方法的区别
             *      Thread类用于描述线程
             *  该类定义了一个功能 用于存储线程要运行的代码 该存储功能就是run方法
             *  主线程 要运行代码 jvm默认规定 是main方法中的内容
             *  我们自己创建的线程 需要运行的内容 一定要放在run方法中
             *  start()方法是用来启动线程的
             * */
             获取线程名称 Thread.currentThread().getName()
             /*
             * 创建线程的方式一 
             * 1.继承Thread类
             * 2.重写run方法 将线程要执行的代码 放在run方法中
             * 3.创建对象 调用start方法 启动线程 使该线程开始执行 java虚拟机调用该线程的run方法
             * */
        实现Runnable接口
            /*
             * 创建线程的方式二
             * 创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。
             * 然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。
             * 1.实现Runnable接口
             * 2.重写Runnable接口中的run方法
             * 3.通过Thread类 建立线程对象
             *     将Runnable接口的子类对象作为参数传递到Thread的构造方法中
             * 4.调用Thread类的start方法 启动线程    
             *         会调用Runnable子类的run方法
             * */

             ******* 真正的线程 是Thread类 或者其子类

        继承Thread类 和 实现Runnable接口的区别
            从扩展的角度而言 最好使用 实现Runnable接口方式
            如果确定只有一个线程的调用就使用继承
            如果需要在继承一个类的同时 还能成为线程 就用实现


        实现Callable接口
            返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。 
            Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
            V call() 
                计算结果,如果无法计算结果,则抛出一个异常。 
            1.实现Callable接口 同时定义泛型  该泛型为call方法的返回值类型
            2.重写call方法 线程要运行的代码
            3.创建FutureTask对象 将Callable接口的实现类进行转换
            4.创建Thread类 传入FutureTask对象
            5.选择性调用FutureTask的get方法 获取call方法的返回值

            Callable产生结果
            FutureTask获取结果
        Runnable 和 Callable的区别?
            相同之处:
                1.都是接口 都是可以用来创建要成为线程的对象
                2.Callable 和 Runnable 都可以用于 线程池中
            不同之处:
                1.Callable 的call方法可以返回一个类型
                  Runnable 的run方法没有明确的返回值 void
                2.Callable 的call方法可以抛出异常
                  Runnable 的run方法不行
                3.Callable 是jdk1.5之后加上的
                  Runnable 是jdk1.0就有

    2.3 线程安全问题
        同步 synchronized 线程锁

             * 问题 发现线程安全性出现了隐患
             *     当多条线程 操作一个共享数据时 一个线程语句执行了一部分 还没执行完
             *  另一个线程参与进来 抢夺了cpu的执行权 造成共享数据的错误
             * 解决方法
             *     对多条线程共享数据 只能一个线程执行完之后 再执行另一个线程
             *  java对于多线程安全问题 提供了专业的解决方案
             *      同步 synchronized
        同步的三种方式:
            同步的前提:
                1.必须是两个 或者 两个以上的线程操作同一个资源
                2.必须是多个线程使用同一个锁 确保锁 的唯一性
            1.同步代码块
                synchronized(锁){
                    要同步的代码
                }
                使用synchronized关键字 加上一个锁
                同步代码块的锁 可以是 任意对象
            2.同步方法
                访问权限修饰符 synchronized 返回值类型 方法名(参数列表){
                    要同步的代码
                }
                同步方法的锁 是 this关键字
            3.静态同步方法
                访问权限修饰符 static synchronized 返回值类型 方法名(参数列表){
                    要同步的代码
                }
                静态同步方法的锁 是 类名.class  就是 类的字节码文件对象
        同步的好处和弊端:
            好处:解决了多线程并发访问的安全问题
            弊端:多了一个判断锁的动作 消耗了内存 程序稍微变慢
        以前的线程安全相关类回顾:
            线程安全
                Vector    HashTable  StringBuffer
            线程不安全
                ArrayList HashMap  StringBuilder
            Collections工具类中 定义了方法 可以将线程不安全 变成线程安全的
                static <T> Collection<T> 
                 synchronizedCollection(Collection<T> c) 
                      返回指定 collection 支持的同步(线程安全的)collection。 
                static <T> List<T> 
                 synchronizedList(List<T> list) 
                      返回指定列表支持的同步(线程安全的)列表。 
                static <K,V> Map<K,V> 
                 synchronizedMap(Map<K,V> m) 
                      返回由指定映射支持的同步(线程安全的)映射。 
                static <T> Set<T> 
                 synchronizedSet(Set<T> s) 
                      返回指定 set 支持的同步(线程安全的)set。 

        Reentrantlock 重入锁
            通过显性定义同步锁对象来实现同步
            一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,
            但功能更强大。 

            提供了更广泛的锁定操作
            lock() 锁
            unlock() 解锁
            注意:这两个方法 需要同时使用 相当于 同步代码块的花括号开始  和 结束
            synchronized(){
                被同步的内容
            }

            区别:
                1.实现的区别
                    synchronized 是依赖于 JVM实现的
                        是操作系统来控制实现
                    ReentrantLock 是JDK实现的
                        是自己敲代码实现的 加锁和解锁
                2.性能区别
                    synchronized 性能略差
                    ReentrantLock 性能稍强
                3.功能区别
                    synchronized 使用比较简洁 由编译器去加锁和解锁
                    ReentrantLock 需要手动声明 来加锁 和 解锁
    死锁(了解)
        在多线程同步的时候 如果同步代码块发生嵌套
        使用了相同的锁 就有可能出现死锁的情况
    如何避免死锁:
        尽量不要嵌套使用同步 synchronized

    案例:
        筷子

        你有一只筷子 我有一只筷子 
        要吃饭
        你不给我 我也不给你
        僵持不下 
        死锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值