Java知识荟萃(为什么实现Serializable接口&volatile关键字解析&对象生死状态)

Java知识荟萃(2019年5月14日)


无敌码农

Java对象为什么要实现Serializable接口

Serializable接口没有任何方法或者字段,只是用于标识可系列化的语义.实现了Serializable接口的类可以被ObjectOutputStream转换为字节流,同时也可以通过ObjectInputStream再将其解析为对象.下面通过代码来讲一个对象保存到文件,并读取的过程:

package com.xiaojian.serializable;

import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = 6021512867207299175L;
    private String name;

    private String password;

    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;
    }
}

测试代码:

package com.xiaojian.serializable;

import java.io.*;

public class TestSerializable {


    public static void main(String[] args) {
        //writerObject();
        readerObject();
    }

    private static void readerObject() {
        try{
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("E:\\user.txt"));
            Object object = inputStream.readObject();
            User user = (User) object;
            System.out.println(user.getName() + "---" + user
            .getPassword());
            inputStream.close();
        }catch(IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private static void writerObject() {
        User user = new User();
        user.setName("张三");
        user.setPassword("123456");
        try{
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("E:\\user.txt"));
            outputStream.writeObject(user);
            outputStream.close();
        }catch(IOException e) {
            e.printStackTrace();
        }
    }
}

如果我们在保存的时候,User类不实现Serializable接口,那么将会抛出一个异常,同样的,在读取文件转换为对象的时候,如果我们修改了User类的Serializable值,同样也会转换错误.

常见的序列化场景:

  • 把内存中的数据保存到文件或者数据库
  • 网络通信时需要用套接字在网络中传送对象时,如我们使用RPC协议进行网络通信时;
volatile关键字

首先,volatile关键字只能修饰类变量和实例变量.方法参数、局部变量、实例常量以及类常量都是不能用volatile修饰的.

原因:volatile关键字是要解决多线程间共享变量的可见性问题的,只有类变量和实例变量才是java中的共享变量的类型,方法参数因为是线程私有,并不存在共享的问题,而常量本身的值是固定的,所以不需要被其修饰

如果volatile修饰的是一个引用数据类型的对象变量,那么该对象作为类变量或实例变量时,其对象中携带的类变量和实例变量也相当于被volatile修饰了.

在并发编程中有三个很重要的特性:

  • 原子性

    在一次操作或者多次操作中,要么所有的操作全部执行,要么全部不执行

  • 可见性

    当一个线程对共享变量进行了修改,那么其他线程可以立刻看到修改的最新值

  • 有序性

    程序代码在执行过程中要确保有数据依赖关系的代码要有先后顺序.

而volatile关键字,就是保证了其中的可见性和有序性,但是不能保证操作的原子性.

在有序性上,它通过增加内存屏障的方式禁止指令重排序,在可见性上,volatile使得它修饰的变量,在被修改以后,会立马刷新同步至主内存,同时将其他线程工作内存中的副本变量置为无效.


石彬的架构笔记

跟面试官聊到JVM,他99%会让你谈谈这个问题!
如何判断一个对象的生死状态?
  1. 引用计数器算法

给每一个对象设置一个引用计数器,每当有一个地方引用这个对象的时候,计数器就加1,每当引用失效的时候就减1.

优点:实现简单、性能高

缺点:增减处理频繁消耗CPU计算,最主要是无法解决循环引用的问题.

  1. 可达性分析算法

通过一系列的"GC Roots"对象作为起始点,从这些对象开始往下搜索,搜索所经过的路径称之为"引用链".

当一个对象到GC Roots没有任何引用链相连的时候,证明此对象是可以被回收的.

在这里插入图片描述

在java中,可作为GC Roots对象的列表:

  • java虚拟机栈中的引用对象
  • 本地方法中JNI引用的对象
  • 方法区中类静态常量的引用对象
  • 方法区中常量的引用对象

对象生死与引用的关系

上面的两种算法,不管是引用计数还是可达性分析,都和对象的"引用"有关,这说明对象的引用决定了对象的生死.

在JDK1.2以后对对象引用进行了扩充,分为:

  • 强引用
  • 软引用
  • 弱引用
  • 虚引用

强引用: 在代码中普遍存在的,类似Object obj = new Object()这种,只要强引用还在,垃圾回收器永远不会回收掉被引用的对象.

软引用: 是一种相对强引用弱化一些的引用,可以让对象豁免一些垃圾回收.只有当jvm认为内存不足时,才会去试图回收软引用指向的对象.jvm会确保在抛出OutOfMemoryError之前,清理软引用指向的对象.

弱引用: 非必须对象,但它的强度比软引用弱,被弱引用关联的对象只能生存到下一次垃圾回收之前.

虚引用: 也成为幽灵引用或幻影引用,是最弱的一种引用关系,无法通过虚引用来获取一个对象实例,为对象设置虚引用的目的只有一个,就是当这个对象被垃圾回收器回收时收到一条系统通知.

死亡标记与拯救

在可达性算法中,不可达的对象,并不是非死不可的,要真正宣告一个对象死亡,至少要经历两次标记的过程.

如果对象在进行可达性分析之后,没有与GC Roots相连接的引用链,它会被第一次标记,并进行筛选,筛选的条件是此对象是否有必要执行finalize()方法.

执行finalize()方法的两个条件:

  1. 重写了finalize()方法
  2. finalize()方法之前没有被调用过,因为对象的finalize()方法只能被执行一次.

如果满足以上两个条件,这个对象将会放置在F-Queue的队列中,并在稍后由一个虚拟机自建的、低优先级FInalizer线程来执行它.

finalize()方法是对象脱离死亡命运最后的机会,如果对象在finalize()方法中重写与引用链上的任何一个对象建立关联,就可以存活.如把自己复制给某个类变量或对象的成员变量.

示例代码:

在这里插入图片描述

执行结果:

执行finalize方法

我还活着

我已经死了

从结果可以看出,任何对象的finalize()方法只会被系统调用一次.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值