对象的序列化和反序列化
- 图解:
- 参与序列化和反序列化的对象,必须实现Serializable,该接口只是一个标志接口,里面没有任何变量和方法。。
- java语言中是采用什么机制来区分类的?
- 第一:首先通过类名进行比对,如果类名不一样,肯定不是同一个类。
- 第二:如果类名一样,再靠序列化版本号进行区分。
- 这种自动生成序列化版本号有什么缺陷?
- 这种自动生成的序列化版本号缺点是: 一且代码确定之后,不能进行后续的修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,这个时候java 虚拟机会认为这是一个全新的类。
- JVM虚拟机看到Serializable接口之后,会自动生成一个序列化版本号。 java虚拟机会默认提供这个序列化版本号。建议将序列化版本号手动的写出来。不建议自动生成。
- transient关键宇表示游离的,不参与序列化。
private transient String name; // name不参与序列化操作!- IDEA工具可以自动生成序列化版本号。
多线程
- 进程和线程
- 进程是一个应用程序,线程是一个进程中的执行程序(执行单元)。一个进程可以启动多个线程
- 进程和进程的内存独立不共享
- 线程A和线程B,堆内存和方法区内存共享,但是栈内存独立,一个线程一个栈。
- 创建线程的方式:
- 创建子类,继承自Thread接口,重写run方法,自定义执行逻辑
/**
* 实现线程的第一种方式 编写一个类,直接继承java.lang.Thread,重写run方法
*/
public class ThreadTest1 {
public static void main(String[] args) {
// 这是main方法,属于主线程,在栈中运行
// 新建一个分支线程对象
MyThread myThread = new MyThread();
// 不会启动线程,不会分配新的分支栈
myThread.run();
/*
* start()方法的作用是:启动一个分支线程,在JVM中开辟-个新的栈空间,这段代码任务完成之后,瞬间就结束了。
* 这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开出来, start()方法就结束了。线程就启动成功了
* 启动成功的线程会自动调用run万法.并且run万法在分支栈的栈底部(压栈)。 run方法在分支栈的栈底部, main方法在主栈的栈底部。run
* 和main是平级的。
*
*/
myThread.start();
// 这里的代码运行在主线程中
for (int i = 0; i < 6; i++) {
System.out.println("主线程-->" + i);
}
}
}
class MyThread extends Thread {
@Override
public void run() {
// 编写程序,这段程序运行在分支栈中
// TODO Auto-generated method stub
super.run();
for (int i = 0; i < 6; i++) {
System.out.println("分支线程---> " + i);
}
}
}
- 创建实现类,实现Runable接口,作为Thread构造方法的参数传入
/**
* 实现现成的第二种方式,编写一个类实现java.lang.Runnable接口
* 这种方式比较常用,因为i一个类实现了接口,还可以去继承其他的类,比较灵活
*
*/
public class ThreadTest2 {
public static void main(String[] args) {
// 创建一个可运行的对象
MyRunnable r = new MyRunnable();
// 将可运行的对象封装成一个线程对象
Thread t = new Thread(r);
// 启动线程
t.start();
for (int i = 0; i < 10; i++) {
System.err.println("主线程-->" + i);
}
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
System.out.println("分支线程-->" + i);
}
}
}
*用匿名内部类的方式实现
public class ThreadTest3 {
public static void main(String[] args) {
// 创建线程对象,采用匿名内部类方式
//通过一个没有名字的类,new出来的对象
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
System.out.println("分支线程-->" + i);
}
}
});
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println("主线程-->" + i);
}
}
}
- 线程生命周期
- 获取线程的名字和当前线程对象
/**
* 1、怎么获取当前线程对象? Thread t = Thread.currentThread() 2.获取线程对象的名字 String string =
* 线程对象.getName() 3、修改线程对象的名字 线程对象.setName("线程名字") 4、当线程没有设置名字的时候,默认的名字有什么规律?
* Thread-0 Thread-1
*
*/
public class ThreadTest4 {
public static void main(String[] args) {
// currentThread就是当前线程对象
// 这个代码出现在main方法当中,所以当前线程就是主线程。
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName());// main
MyThread1 myThread = new MyThread1();
System.out.println(myThread.getName());
// 设置线程名字
myThread.setName("分支线程-0");
// 获取线程名字
String string = myThread.getName();
System.out.println(string);
myThread.start();
}
}
class MyThread1 extends Thread {
@Override
public void run() {
Thread currentThread = Thread.currentThread();
System.out.println(this.getName());
System.out.println(super.getName());
//此方法更通用
System.out.println(currentThread.getName());// 分支线程-0
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
System.out.println("分支线程-->" + i);
}
super.run();
}
}
- sleep()方法:静态方法,与对象无关,t.sleep()不会让t进入休眠,而是会转换成Thread.sleep(),让当前进程进入休眠。
/**
* 关于线程的sleep方法: static void sleep(long millis)
* 1、静态方法: Thread.sleep( 1000);
* 2、参数是毫秒
* 3、作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其它线程使用。 这行代码出现在A线程中, A线程就会进入休眠。与对象无关。
* 这行代码出现在B线程中, B线程就会进入休眠。
* 4. Thread. sleep()方法,可以做到这种效果:
* 间隔特定的时间,去执行-段特定的代码,每隔多久执行一次。
*
*/
public class ThreadTest5 {
public static void main(String[] args) {
// 让当前线程进入休眠,睡眠5秒
// 当前线程是主线程! ! !
/*
* try { Thread.sleep(1000 * 5); } catch (InterruptedException e) {
* e.printStackTrace(); }
*/
// 5秒之后执行这里的代码
// System.out.println("hello world!");
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "--->" + i);
// 睡眠1秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 如何终止睡眠:thread.interrupt()
/**
* sleep睡太久,如何唤醒一个正在睡眠的进程?
* 注意:这个不是中断线程的执行,是终止线程的睡眠
*/
public class ThreadTest6 {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable2());
thread.setName("thread");
thread.start();
//希望五秒之后,让线程醒来
try {
Thread.sleep(1000*5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//中断thread线程睡眠(这种中断处理机制依靠了java的异常处理机制)
thread.interrupt();
}
}
class MyRunnable2 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"---> begin");
//子类重写不能比父类抛出更多的异常,只能try...catch
//run()方法中只能try...catch,因为run()在父类中没有抛出异常
try {
//休眠一小时
Thread.sleep(1000*60*60);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"---> end");
}
}
- 强行中断线程执行,设置run()方法的flag标签
/**
* 在java中如何合理的强行终止一个线程的执行,不会造成数据的丢失
*
*/
public class ThreadTest7 {
public static void main(String[] args) {
MyRunnable3 myRunnable3 = new MyRunnable3();
Thread thread = new Thread(myRunnable3);
thread.setName("thread");
thread.start();
// 模拟五秒
try {
thread.sleep(1000 * 5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 终止线程
// 什么时候想终止线程,把标记修改为false就可以了
myRunnable3.run = false;
}
}
class MyRunnable3 implements Runnable {
// 打一个boolean标记
boolean run = true;
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
if (run) {
System.out.println(Thread.currentThread().getName() + "--->" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
return;
}
}
}
}
- 进程调度方法
- 实例方法:
- void setpriority (int newPriority) 设置线程的优先级
- int getpriority() 获取线程优先级。
- 最低优先级1。默认优先级是5。最高优先级10。优先级比较高的获取CPU时间片可能会多一些。
- 静态方法:
- static void yield() 让位方法暂停当前正在执行的线程对象,并执行其他线yield()方法不是阻塞方法。让当前线程让位,让给其它线程使用.yield()方法的执行会让当前线程从"运行状态”回到"就绪状态"。
- 线程共享数据
建立学生类,线程1用于生成随机的学生成绩,线程2用于计算学生的总成绩和平均分.
StudentTest :
/**
由于线程推进的不同步,导致最终生成的学生对象的个数>统计的个数
*/
public class StudentTest {
static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
//boolean flag = false;
//Local variable flag defined in an enclosing scope must be final or effectively final
//在封闭范围中定义的局部变量标志必须是最终的或有效的最终的
System.out.println("主线程开始!");
Class class1 = new Class();
// 线程1负责添加学生
Runnable runnable = new Runnable() {
int sum = 0;
int count = 0;
@Override
public void run() {
System.out.println("线程1创建学生对象启动!");
// TODO Auto-generated method stub
while (true) {
int score = (int) ((Math.random() * 100));
Student s = new Student(score);
count++;
System.out.println("第 " + count + " 的学生的成绩为:" + score);
class1.addStudent(s);
if (flag) {
System.out.println("第二个线程else中输出平均分的线程结束,flag值置ture,线程1最终结束");
break;
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
// 在指定的毫秒数内让当前“正在执行的线程”休眠(暂停执行)。
Thread.sleep(1);
// 线程2:计算学生总分和平均成绩
Runnable runnable2 = new Runnable() {
int sum = 0;
int count = 0;
public void run() {
System.out.println("线程2计算学生总分和平均成绩启动!");
while (true) {
Student student = class1.getStudent();
if (student != null) {
sum += student.getGrade();
count++;
System.out.println("共有学生:" + count + " 学生的总分为:" + sum);
} else {
System.out.println("平均分:" + sum * 1.0 / count);
flag = true;
break;
}
}
}
};
// 同时启动三个线程2计算成绩
/*
* for (int i = 0; i < 2; i++) { Thread thread2 = new Thread(runnable2);
* thread2.start(); }
*/
Thread thread2 = new Thread(runnable2);
thread2.start();
System.out.println("主线程结束!");
}
}
Student类:
public class Student {
private int grade;
public Student(int grade) {
super();
this.grade = grade;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
}
Class类:
import java.util.ArrayList;
public class Class {
private ArrayList<Student> arrayList = new ArrayList<Student>();
public Class() {
}
public void addStudent(Student student) {
arrayList.add(student);
}
public Student getStudent() {
if (arrayList.size() > 0) {
Student student1 = arrayList.get(0);
arrayList.remove(0);
return student1;
}
return null;
}
}