java基础 day13-对象的序列化和反序列化,多线程

对象的序列化和反序列化

  • 图解:在这里插入图片描述
  • 参与序列化和反序列化的对象,必须实现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;
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值