Java基础知识
- Java对象的复制
- Java序列化
- Java线程
- Java多线程同步
- Java网络IO编程
1. Java对象的复制
对于Java语言来说,数据类型可以分为基本数据类型和引用类型,而数据复制操作针对不同的类型具有不同的含义。数据复制可以分为浅复制和深复制。
对于基本数据类型而言,深浅复制无差,但对于引用类型却有区别。浅复制,复制的是引用,即对象的地址或者引用,一旦原来对象的引用所指地址内的数据发生变化,复制后的对象也会随之变化。深复制,复制的是引用所指地址内的数据,复制后的对象不会随着原对象中数据的变化而变化。
2. Java序列化
定义
Java对象序列化是指将那些实现Serializable接口的对象转化成一个字节序列。序列化后可以弥补不同操作系统之间的差异。而反序列化是序列化的逆过程,将字节序列恢复成原对象。应用
Java的远程方法调用(RMI)、JavaBean的序列化实现方式
1、实现Serializable接口,该方法能够序列化对象的所有属性。
2、实现ExternalSerializable接口,该方法可以自定义要序列化的属性。常用的序列协议
- XML序列: 性能很差,冗余大。 - Json: 过于冗余 - Protobuf、Avro:这两种是目前比较优越的。
注意点
带static修饰的属性不会被序列化;对象的类名、属性(除方法)均会被序列化。
3. Java线程
线程的实现方式
Java中对线程的是实现方式有三种,如下所示:
(1) 实现Runable接口,实现run()。示例代码如下:
public class MyThread1 implements Runnable{
public void run(){
//具体方法
System.out.println("实现Runable接口");
}
public static void main(String[]args){
MyThread1 mt=new MyThread1();
Thread thread=new Thread(mt);//以类MyThread1 为参数实例化一个Thread类对象
thread.start();//启动线程
}
}
(2) 继承Thread类,重写run()。
public class MyThread2 extends Thread{
public void run(){
//具体方法
System.out.println("继承Thread类");
}
public static void main(String[]args){
MyThread2 mt=new MyThread2();
mt.start();//启动线程
}
}
以上两种方法需要start()来启动线程,之后JVM将线程放入就绪队列,等到可运行时再执行run(),无返回值,也不会抛出异常。
(3)实现Callable接口,实现call(),该方法不常用。有返回值,会抛出异常。
线程中start()和run()函数的区别
start():用来启动线程,实现真正的多线程。调用start()之后,线程并不是马上执行,而是先进入就绪状态,一旦有空闲cpu,就会开始调用run()执行。
run():该方法是Thread类的一个方法,并没有实现多线程。如果直接调用run(),只有主线程会被执行。注意点
启动线程,并不一定要调用start()方法,可通过建立一个Handler对象handler,并调用post(Runnable r)方法,即handler.post(r)便可实现线程的启动,这一过程相当于在原线程内直接调用run()方法,并没有建立新的线程。
4. Java多线程同步
多线程同步方法
Java可以实现多线程同步的方式有多种,这里主要介绍下面几种:
- 同步方法: 用Synchronized修饰方法,可以保护整个方法只能被当前线程访问。
- 同步代码块: 用Synchronized修饰语句块。
- 可见性(仅用于变量):用Volatile修饰变量,使得变量在发生变化时能够第一时间让所有其他线程知晓。不会阻塞其他线程,也不是原子操作,不能用于修饰final变量。
- 可重入锁: 通过实现Lock接口的ReentrantLock类实现。同一线程外层函数获得锁之后,内层递归函数仍有获锁代码,但不会受到影响。
- ThreadLocal:在本地创建线程变量,该变量的读写操作完全独立于其他线程操作,主要参考了“以空间换时间”的思想。
Synchronized和Lock的区别
Synchronized属于隐式锁,适用于并发量较小情况,是在JVM层实现的,系统可以监控锁的释放。
而Lock是显示锁,需要在加解锁处用代码指出lock()和unlock()(在finally处显示释放锁),适用于并发量较大情况。Synchronized和Volatile异同
同: 两者均为了保证多线程读写数据后数据的一致性。
异: Synchronized会锁定所修饰的对象,只允许当前线程访问,其他需要访问该对象的线程被阻塞,保证了对象的可见性和原子性。
Volatile是将所修饰的对象拷贝一份后进行读写操作,结束后立马更新主存中原对象,过程中并不会阻塞其他线程,只具有可见性,无原子性。另外,Volatile还可以防止指令重排,在单例模型中有应用。
5. Java网络IO编程
- 传统BIO:同步并阻塞服务器通信模式,一个客户端一个线程(一个连接一个线程),即每次客户端发出一个请求,服务器端通过独立的一个Acceptor线程负责管理,创建一个新线程来处理。适用于连接数目少且固定的架构。
- 伪异步I/O:用线程池管理Acceptor线程管理的线程,即服务器端可以用1个或N个线程来处理客户端的M个连接请求(M>>N),底层依旧是同步阻塞I/O。
- NIO:同步非阻塞服务器通信模式,一个请求一个线程,利用多路复用器Selector轮询,一个Selector可以处理成千上万个客户端连接。适用于连接数目多且连接时间较短的操作。如聊天服务器。
- AIO:异步非阻塞服务器通信模式,一个有效请求一个线程,无需启动线程,即先由操作系统完成I/O请求,再通知服务器,被动回调处理客户端的有效请求。