java基础知识总结(四)
本文主要介绍一下几个方面:
1.多线程
2.I/O
3.对象序列化
4.异常处理
1.多线程
线程是在一个进程中并发的一个顺序执行的流程。
线程的组成:
1.cup 有OS负责分配
2.Data 堆空间:存储对象(存储实例变量) 栈空间:存储局部变量。
3.Code 由程序员指定 继承Thread类或者实现Runnable接口。
实现方式:
1.继承Thread 一个Thread对象表示一个线程
eg:
class myThread extends Thread
{
public void run()
{
System.out.println("this is a test");
}
}
2.实现Runnable接口
eg:
/**
* 通过实现Runnable接口创建一个线程
* @author DreamSea
*/
public class ThreadTest implements Runnable {
public void run() {
System.out.println("I'm running!");
}
}
线程运行状态如下图:
thread.jpg
线程的状态:
新生状态(New): 当一个线程的实例被创建即使用new关键字和Thread类或其子类创建一个线程对象后,此时该线程处于新生(new)状态,处于新生状态的线程有自己的内存空间,但该线程并没有运行,此时线程还不是活着的(not alive);
就绪状态(Runnable): 通过调用线程实例的start()方法来启动线程使线程进入就绪状态(runnable);处于就绪状态的线程已经具备了运行条件,但还没有被分配到CPU即不一定会被立即执行,此时处于线程就绪队列,等待系统为其分配CPCU,等待状态并不是执行状态; 此时线程是活着的(alive);
运行状态(Running): 一旦获取CPU(被JVM选中),线程就进入运行(running)状态,线程的run()方法才开始被执行;在运行状态的线程执行自己的run()方法中的操作,直到调用其他的方法而终止、或者等待某种资源而阻塞、或者完成任务而死亡;如果在给定的时间片内没有执行结束,就会被系统给换下来回到线程的等待状态;此时线程是活着的(alive);
阻塞状态(Blocked):通过调用join()、sleep()、wait()或者资源被暂用使线程处于阻塞(blocked)状态;处于Blocking状态的线程仍然是活着的(alive)
死亡状态(Dead):当一个线程的run()方法运行完毕或被中断或被异常退出,该线程到达死亡(dead)状态。此时可能仍然存在一个该Thread的实例对象,当该Thready已经不可能在被作为一个可被独立执行的线程对待了,线程的独立的call stack已经被dissolved。一旦某一线程进入Dead状态,他就再也不能进入一个独立线程的生命周期了。对于一个处于Dead状态的线程调用start()方法,会出现一个运行期(runtime exception)的异常;处于Dead状态的线程不是活着的(not alive)。
在线程t1中调用t2.join() t1阻塞,当t2进入终止状态时,t1回到可运行状态。
线程同步:
当多线程并发访问临界资源(同一对象)时,如果破坏了原子操作(不可分割的操作),就会造成数据不一致。
//对o进行加锁的同步代码块
Synchronized(o)
{
}
任何对象都有一个互斥锁标记,用来分配给线程,只有拿到对象锁标记的线程,才能进入对该对象加锁的同步代码块。运行结束,线程进入同步代码块,释放锁标记
只用线程拿到对象的锁标记才能进入代码块。
锁池:任何对象都有一个空间,用来存放等待该对象锁标记的线程。
一个线程可以同时拥有多个对象锁标记,当线程阻塞在锁池中事,不会释放已拥有的锁标记,由此可能造成死锁。所以就有了线程间的通信。
线程间的通信:
任何对象都有一个等待队列,用来存放线程。
t1:o.wait(),必须放在对o加锁的同步代码块中,t1会释放它拥有的锁标记,同时t1阻塞在o的等待队列中。
t2:o.notify()/notifyAll(),必须放在对o加锁的同步代码块中,从o的等待队列中,释放一个或全部线程。
2.I/O
java.iO.File
File 对象,代表磁盘上的一个文件或者目录
File f = new File("F:\\file.text");
方法:
f.createNewFile():创建文件
f.delete():删除
f.mkdir():创建文件夹
f.exists():判断文件或目录是否存在
f.isDirectory():判断文件对象所代表的是否是目录
f.isFIle():是否是文件
f.getAbsolutePatyh():获得绝对路径
遍历:
eg:
File file = new File("F:\\javaTest");
File[] fs = file.listFiles();
for (File file2 : fs)
{
System.out.println("路径是:+"+file2.getAbsolutePath());
}
如果只想特殊后缀文件,如.zip
可以使FileFilter过滤文件
eg:
package test;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.nio.file.DirectoryStream.Filter;
public class ThreadFile {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
File file = new File("F:\\javaTest");
File[] fs = file.listFiles(new myFilter());
for (File file2 : fs)
{
System.out.println("路径是:+"+file2.getAbsolutePath());
}
}
}
class myFilter implements FileFilter
{
public boolean accept(File f)
{
if (f.isDirectory())
{
return false;
}
else {
if (f.getName().endsWith(".zip"))
{
return true;
}
else {
return false;
}
}
}
}
另一种写法:
eg:
File file = new File("F:\\javaTest");
File[] fs = file.listFiles(new FileFilter() {
@Override
public boolean accept(File arg0) {
// TODO Auto-generated method stub
if (arg0.isDirectory())
{
return true;
}
if (arg0.isFile())
{
if (arg0.getName().endsWith(".zip"))
{
return true;
}
}
else
{
return false;
}
return false;
}
});
for (File file2 : fs)
{
if (file2.isFile())
{
System.out.println(file2.getAbsolutePath());
}
else {
System.out.println(file2);
}
}
I/O流
流:对象,用来子啊JVM和外部数据员之间传输数据
按照不同的方面划分可以划分为不同的流
按照数据方向:输入流 / 输出流
按照数据的单位:字节流 / 字符流
按照流的功能:节点流 / 过滤流
字节流:以字节为单位,可以处理一切数据
字符流:以字符为单位,只能处理文本数据
节点流:实际传输数据的流
过滤流:给节点流增强功能
InputStream / OutputStream 字节流父类
FileInputStream / FileOutputStream 字节流实现类
创建输出流代码为:
OutputStream os = new FileOutputStream("F:\\javaTest\2.text",true);
文件不存在会自动创建
true:表示文件存在会追加
false:会覆盖以前的文件
方法:
write(int a):把字节a写进去
write(byte[] bs):把字节数组bs全部写进去
write(byte[] bs,int off,int len):把字节数组的一段写出去,有off位置len个数
输出流FileInputStream
用于读取一个文件
eg:
InputStream input = new FileInputStream("2.text");
while(true)
{
int i = input.read();
if (i == -1)
{
break;
}
else {
System.out.println((char)i);
}
}
input.close();
int read():从文件中读取一个字节,返回-1结束
int read(byte[] bs):从文件中读取多个字节,bs:返回值为实际读到的字节数,以-1结束。
int read(byte[] bs,int off,int len):从文件中读的多个字节,放入bs中的一段,返回值为实际读到的字节数,以-1为结束。
过滤流:DataInputStream / DataOutputStream
过滤是为了增加节点流的功能,直接读写八种基本类型和字符串
(对字符串的读/写方法是reatUTF/writeUTF)
,eg:写入一个长整形
OutputStream os = new FileOutputStream("1.text",true);
DataOutputStream out = new DataOutputStream(os);
out.writeLong(10000);
out.close();
使用流读写文件一般分为四步:
1.创建节点流
2.封装过滤流
3.读 / 写 数据
4.关闭流
缓冲数据流(一般写文件时用的较多)
eg:
FileOutputStream fos = new FileOutputStream("1.txt");
BufferedOutputStream out = new BufferedOutputStream(fos);
out.write('a');
out.flush();
out.close();
PrintStream :写8种基本数据类型,缓冲。
RandomAccessFile:随机访问文件。
字符流
Reader/writer 字符流父类
FileReader / FileWriter 文件字符流,节点流。
BufferedReader / BufferedWrite(一般用Printwrite替代,采用默认编码方式) 缓冲流 过滤流。
InputStreamReader / PrintWriter 桥转换,把字节流转换为字符流。
在转换时指定编码方式。
eg:
FileOutputStream fos = new FileOutputStream("1.txt");
BufferedOutputStream out = new BufferedOutputStream(fos);
Writer wir = new OutputStreamWriter(out, "GBK");
wir.write('s');
wir.close();
3.对象序列化
对象序列化:将对象通过流传输
ObjectOutputStream / ObjectInputStream
只有实现了Serializable接口的对象才能初始化。不仅对象本身需要实现Serializable接口,对象属性也需要实现该接口。用transient修饰的属性不参与序列化。
eg:对象XulieHuaTest
package test;
import java.io.Serializable;
public class XulieHuaTest implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
int age;
String name;
XulieHuaTest(int age,String name)
{
this.age=age;
this.name = name;
}
}
写入
FileOutputStream s = new FileOutputStream("1.text");
ObjectOutputStream os= new ObjectOutputStream(s);
XulieHuaTest one1 = new XulieHuaTest(20, "ss");
os.writeObject(one1);
os.close();
读取
FileInputStream r = new FileInputStream("1.text");
ObjectInputStream read = new ObjectInputStream(r);
XulieHuaTest sHuaTest = (XulieHuaTest)read.readObject();
System.out.println("age+"+sHuaTest.age+"+name+"+sHuaTest.name);
read.close();
4.异常处理
java中的异常处理有两种
1.throws 声明抛出 沿着调用链反向处理 属于消极处理。
public void testException() throws IOException
{
//FileInputStream的构造函数会抛出FileNotFoundException
FileInputStream fileIn = new FileInputStream("E:\\a.txt");
int word;
//read方法会抛出IOException
while((word = fileIn.read())!=-1)
{
System.out.print((char)word);
}
//close方法会抛出IOException
fileIn.clos
}
2.try...catch...finally 积极处理
public static void main(String[] args){
try {
foo();
}catch(ArithmeticException ae) {
System.out.println("处理异常");
ae.printStackTrace();
}
}
public static void foo(){
int a = 5/0; //异常抛出点
System.out.println("这是一个测试!!"); //////////////////////不会执行
}
方法覆盖,抛异常的子类不能比父类抛出更多的异常。