目录
序列化流:把对象按照流一样的方式存到文本文件或者数据库或者网络中传输等
反序列化:把文本文件中的流对象数据或者网络中的流数据给还原成一个对象。
序列化流:把对象按照流一样的方式存到文本文件或者数据库或者网络中传输等
对象---流数据:ObjectOutputStream
反序列化:把文本文件中的流对象数据或者网络中的流数据给还原成一个对象。
数据流 --- 对象:ObjectInputStream
未序列化异常:
java.io.NotSerializableException
类的序列化由实现java.io.Serializable接口的类启用。
不可实现此类接口的类将不会使任何序列化或反序列化。
可序列化类的所有子类型都是可序列化的。
序列化接口没有方法或字段,仅用于标识可串化的语义。
java.io.InvalidClassException: com.shujia.java.day23.Person;
local class incompatible:
stream classdesc serialVersionUID = 6760410433349567446,
local class serialVersionUID = -6862371829361004873
Person类实现了Serializable标记接口,它本身就应该有一个标记值。
假设一开始这个标记值为id=100
在没有修改Person类之前:
Person.class -- id = 100
写数据的时候:obj.txt -- id = 100
读数据的时候:obj.txt -- id = 100
进行修改之后:(把private删了)
Person.class -- id =200
写数据的时候:obj.txt -- id =100
读数据的时候:obj.txt -- id =100
实际开发中,我们因业务问题,不允许重复往文件或者某数据库中重复存储(写入)
这个问题是由于id值的不匹配(class文件的id值与文件中存储对象的id不匹配)导致的。让ID值固定就好了。
JAVA在序列化中提供了一个ID值,可以让我们去设定。serialVersionUID
需求:
现在我不想再序列化的时候把年龄也序列化到文件中,java提供了一个关键字,可以让我们在序列化的时候选择哪些成员不被序列化:transient
=====================================================================
线程
如果程序可以用一条路径来表示,这个程序就是单线程程序。如果一个程序可以用多条执行路径来表示,这个程序就是多线程程序。
关键词:
并行:指的是逻辑上同时发生,指在某一段时间段内同时运行多个程序
并发:指的是物理上的同时发生,指在某一个时间点上同时运行多个程序
JAVA程序的运行原理:
java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。
该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法,所以main方法运行在主线程中,在此之前的所以程序都是单线程的。
JVM启动的时候是单线程还是多线程呢?
多线程。
主线程
垃圾回收线程
所以在JVM启动的时候,最低要求有两个线程,JVM启动的时候是多线程的。
创建线程的第一种方式:继承Thread类
步骤:
1、自定义一个子类,继承Thread类
2、自定义重写Thread类的run()方法
3、创建子类对象
4、启动线程
面试题:调用run()与调用start()的区别
run()的调用仅仅是封装了被线程执行的代码,但是直接调用的话是普通的方法调用
start()方法的调用,首先单独启动了一个线程,然后再由JVM去调用该线程的run()方法
如何获取和设置线程名字?
通过构造方法给线程起名字:
Thread(String name) 分配一个新的Thread对象。
通过方法给线程起名字:
void setName(String name) 将此线程的名称更改为等于参数name
如何获取线程名字:
getName():
如何获取main方法的主线程:
public static Thread currentThread()返回对当前正在执行的线程对象的引用
后台线程(守护线程):
JAVA中有两类线程:用户线程、守护线程
用户线程:我们在学习多线程之前所有的程序代码,运行起来都是一个个的用户线程
守护线程:所谓的守护线程,指的就是程序运行的时候在后台提供了一种通用服务的线程。比如说垃圾回收线程,它就是一个称职的守护者,并且这种线程并不属于程序不可或缺的部分。所以非守护线程结束的时候,程序也就终止了,同时会杀死进程中所有的守护线程。
反过来说,只要程序中存在非守护者线程,程序就不会终止。
如何设置守护线程:
public final void setDaemon(boolean on)
通过这个方法将该线程对象标记为守护者线程或者非守护者线程
当运行的程序只有一个且式是守护者线程的时候,java虚拟机退出
注意:将线程设置为守护者线程这一步,必须在启动前设置
加入线程:
public final void join():其他线程等待这个线程死亡:
注意:在线程设置为加入线程之前,先将该线程变为就绪状态,也就是调用start()
设置优先级(默认5)
获取线程的优先级
public final int getPriority()返回此线程的优先级
设置线程的优先级
public final void setPriority(int newPriority)更改此线程的优先级1-10
newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY
线程优先级高仅仅表示的是获取CPU时间片的几率会高一些,但是不是绝对一定会获取
中断线程:
public final void stop():让正在运行的线程停止,run方法剩下的代码不会执行,这个方法过时了,被弃用了,但是还能使用。
public void interrupt():中断正在运行的线程,被中断的线程将run方法执行完毕,并抛出异常
java.lang.InterruptedException: sleep interrupted
礼让线程:
public static void yield()
暂停当前正在执行的线程对象,并执行其他线程
它的作用是为了让多个线程之间更加和谐一点,并不能一定保证多个线程一人一次执行
publi static void sleep()
休眠进程
我们刚刚加入延迟的卖票程序出现的问题称之为线程安全问题。 要想解决这个问题,就应该去考虑哪些原因导致这些问题存在: (这三点,也是今后我们去判断一个程序是否存在线程安全的标准,缺一不可) 1、是否存在多线程环境 2、是否存在共享数据/共享变量 3、是否有多条语句操作着共享数据/共享变量 回想一下刚刚的卖票程序是否满足以上条件: 1、是否存在多线程环境 是,由于有三个线程模拟三个窗口 2、是否存在共享数据/共享变量 是 共享数据是100张票 3、是否有多条语句操作着共享数据/共享变量 是 由此可见,我们上一个程序出现问题是一个正常的现象,因为它同时满足以上三个条件 如何解决这些问题呢? 第一、二两个原因条件是我们改变不了的,我们只能想办法改变第三个原因条件,只要其中一个不满足 就不会发生线程安全问题。 解决问题的思想: 要是有一个办法可以让多条语句控制共享数据包成一个整体,在某个线程执行的时候,别的线程进不来 知道某个线程执行完毕一次run方法之后,别的线程再进来。 Java提供了一个机制给我们使用,解决线程安全的问题:同步安全机制 解决方式1: 同步代码块: 格式: synchronized(对象){ 需要同步的代码; } 1、这里的对象是什么呢? 随便创建一个对象试试 2、需要同步的代码又是什么呢? 操作共享变量的代码块