1,获取线程的名称:
1.使用Thread类中的方法getName()
getName() 返回该线程的名称。
2.可以先获取到当前正在执行的线程,使用线程中的方法getName()获取线程的名称
Thread.currentThread() 返回对当前正在执行的线程对象的引用。
2, Thread.sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
毫秒数结束之后,线程继续执行
3,创建多线程程序的第二种方式:实现Runnable接口
java.lang.Runnable
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。
java.lang.Thread类的构造方法
Thread(Runnable target) 分配新的 Thread 对象。
Thread(Runnable target, String name) 分配新的 Thread 对象。
实现步骤:
1.创建一个Runnable接口的实现类
2.在实现类中重写Runnable接口的run方法,设置线程任务
3.创建一个Runnable接口的实现类对象
4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
5.调用Thread类中的start方法,开启新的线程执行run方法
实现Runnable接口创建多线程程序的好处:
1.避免了单继承的局限性
一个类只能继承一个类(一个人只能有一个亲爹),类继承了Thread类就不能继承其他的类
实现了Runnable接口,还可以继承其他的类,实现其他的接口
2.增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
实现类中,重写了run方法:用来设置线程任务
创建Thread类对象,调用start方法:用来开启新线程
4, 匿名内部类方式实现线程的创建
匿名:没有名字
内部类:写在其他类内部的类
匿名内部类作用:简化代码
把子类继承父类,重写父类的方法,创建子类对象合一步完成
把实现类实现类接口,重写接口中的方法,创建实现类对象合成一步完成
匿名内部类的最终产物:子类/实现类对象,而这个类没有名字
格式:
new 父类/接口(){
重复父类/接口中的方法
5, 解决线程安全问题的一种方案:使用同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:
1.通过代码块中的锁对象,可以使用任意的对象
2.但是必须保证多个线程使用的锁对象是同一个
3.锁对象作用:
把同步代码块锁住,只让一个线程在同步代码块中执行
6,解决线程安全问题的二种方案:使用同步方法
使用步骤:
1.把访问了共享数据的代码抽取出来,放到一个方法中
2.在方法上添加synchronized修饰符
格式:定义方法的格式
修饰符 synchronized 返回值类型 方法名(参数列表){
可能会出现线程安全问题的代码(访问了共享数据的代码)
静态的同步方法
锁对象是谁?
不能是this
this是创建对象之后产生的,静态方法优先于对象
静态方法的锁对象是本类的class属性-->class文件对象(反射)
7,
解决线程安全问题的三种方案:使用Lock锁
java.util.concurrent.locks.Lock接口
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
Lock接口中的方法:
void lock()获取锁。
void unlock() 释放锁。
java.util.concurrent.locks.ReentrantLock implements Lock接口
使用步骤:
1.在成员位置创建一个ReentrantLock对象
2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
8, Obejct类中的方法
void wait()
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
void notify()
唤醒在此对象监视器上等待的单个线程。
会继续执行wait方法之后的代码
9, 进入到TimeWaiting(计时等待)有两种方式
1.使用sleep(long m)方法,在毫秒值结束之后,线程睡醒进入到Runnable/Blocked状态
2.使用wait(long m)方法,wait方法如果在毫秒值结束之后,还没有被notify唤醒,就会自动醒来,线程睡醒进入到Runnable/Blocked状态
唤醒的方法:
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
1,线程间通信
等待唤醒机制三个方法:
wait();放弃cup的执行权
notify();
notifyAll();
wait和notify必须是相同的锁!
2,Lambda表达式(简化代码)
只有函数式接口才能够使用(只有一个抽象方法)
格式:(参数列表)->{一些重写方法的代码}
Lambda表达式可省略的内容:
1,(参数列表):括号中参数列表的数据类型,可以省略不写
2,(参数列表):括号中的参数如果只有一个,那么类型和()都可以省略
3,{一些代码}:如果{ }中的代码只有一行,无论是否有返回值,都可以省略{};return;分号
注意:要省略{},return,分号必须一起省略
3,线程池:JDK1.5之后提供的
java.util.concurrent.Executors:线程池的工厂类,用来生成线程池
Executors类中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池
参数:
int nThreads:创建线程池中包含的线程数量
返回值:
ExecutorService接口,返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口接收(面向接口编程)
java.util.concurrent.ExecutorService:线程池接口
用来从线程池中获取线程,调用start方法,执行线程任务
submit(Runnable task) 提交一个 Runnable 任务用于执行
关闭/销毁线程池的方法
void shutdown()
线程池的使用步骤:
1.使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池
2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
3.调用ExecutorService中的方法submit,传递线程任务(实现类),开启线程,执行run方法
4.调用ExecutorService中的方法shutdown销毁线程池(不建议执行)
1,File类:
文件和目录路径名的抽象表现形式。
java把电脑中的文件和文件夹(目录)封装为了一个File类,我们可以使用File类对文件和文件夹进行操作
File类是一个与系统无关的类,任何的操作系统都可以使用这个类中的方法
重点:记住这三个单词
file:文件
directory:文件夹/目录
path:路径
File parent = new File("c:\\");
File file = new File(parent,"hello.java");
String getAbsolutePath() :返回此File的绝对路径名字符串。
String getPath() :将此File转换为路径名字符串。(toString方法调用的就是getPath方法)
String getName() :返回由此File表示的文件或目录的名称。
long length() :返回由此File表示的文件的长度。(如果构造方法中给出的路径不存在,那么length方法返回0)
boolean exists() :此File表示的文件或目录是否实际存在。
boolean isDirectory() :此File表示的是否为目录。
boolean isFile() :此File表示的是否为文件。( 这两个方法使用前提,路径必须是存在的,否则都返回false)
boolean createNewFile() :当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。
boolean delete() :删除由此File表示的文件或目录。
boolean mkdir() :创建由此File表示的目录。
boolean mkdirs() :创建由此File表示的目录,包括任何必需但不存在的父目录。
String[] list() :返回一个String数组,表示该File目录中的所有子文件或目录。
File[] listFiles() :返回一个File数组,表示该File目录中的所有的子文件或目录。
2,递归:方法自己调用自己
- 递归的分类:
- 递归分为两种,直接递归和间接递归。
- 直接递归称为方法自身调用自己。
- 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。
- 注意事项:
- 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
- 在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
- 构造方法,禁止递归
递归的使用前提:
当调用方法的时候,方法的主体不变,每次调用方法的参数不同,可以使用递归
3,过滤文件
在File类中有两个和ListFiles重载的方法,方法的参数传递的就是过滤器
File[] listFiles(FileFilter filter)
java.io.FileFilter接口:用于抽象路径名(File对象)的过滤器。
作用:用来过滤文件(File对象)
抽象方法:用来过滤文件的方法
boolean accept(File pathname) 测试指定抽象路径名是否应该包含在某个路径名列表中。
参数:
File pathname:使用ListFiles方法遍历目录,得到的每一个文件对象
File[] listFiles(FilenameFilter filter)
java.io.FilenameFilter接口:实现此接口的类实例可用于过滤器文件名。
作用:用于过滤文件名称
抽象方法:用来过滤文件的方法
boolean accept(File dir, String name) 测试指定文件是否应该包含在某一文件列表中。
参数:
File dir:构造方法中传递的被遍历的目录
String name:使用ListFiles方法遍历目录,获取的每一个文件/文件夹的名称
注意:
两个过滤器接口是没有实现类的,需要我们自己写实现类,重写过滤的方法accept,在方法中自己定义过滤的规则
File[] files = dir.listFiles(pathname->pathname.isDirectory() || pathname.getName().toLowerCase().endsWith(".java"));
过滤的规则:
在accept方法中,判断File对象是否是以.java结尾
是就返回true
不是就返回false
如果pathname是一个文件夹,返回true,继续遍历这个文件夹
1, FileOutputStream 文件字节输出流:
close() :关闭此输出流并释放与此流相关联的任何系统资源。
flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
write(byte[] b):将 b.length字节从指定的字节数组写入此输出流。
write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
write(int b) :将指定的字节输出流。
写入数据的原理(内存-->硬盘)
java程序-->JVM(java虚拟机)-->OS(操作系统)-->OS调用写数据的方法-->把数据写入到文件中
字节输出流的使用步骤(重点):
1.创建一个FileOutputStream对象,构造方法中传递写入数据的目的地
2.调用FileOutputStream对象中的方法write,把数据写入到文件中
3.释放资源(流使用会占用一定的内存,使用完毕要把内存清空,提供程序的效率)
追加写/续写:使用两个参数的构造方法
FileOutputStream(String name, boolean append)创建一个向具有指定 name 的文件中写入数据的输出文件流。
FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
参数:
String name,File file:写入数据的目的地
boolean append:追加写开关
true:创建对象不会覆盖源文件,继续在文件的末尾追加写数据
false:创建一个新文件,覆盖源文件
写换行:写换行符号
windows:\r\n("\r\n".GetBytes)
linux:/n
mac:/r
2,FileInputStream:文件字节输入流
定义了所有子类共性的方法:
read()从输入流中读取数据的下一个字节。
read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
close() 关闭此输入流并释放与该流关联的所有系统资源。
读取数据的原理(硬盘-->内存)
java程序-->JVM-->OS-->OS读取数据的方法-->读取文件
字节输入流的使用步骤(重点):
1.创建FileInputStream对象,构造方法中绑定要读取的数据源
2.使用FileInputStream对象中的方法read,读取文件
3.释放资源
发现以上读取文件是一个重复的过程,所以可以使用循环优化
不知道文件中有多少字节,使用while循环
while循环结束条件,读取到-1的时候结束
布尔表达式(len = fis.read())!=-1
1.fis.read():读取一个字节
2.len = fis.read():把读取到的字节赋值给变量len
3.(len = fis.read())!=-1:判断变量len是否不等于-1
3, FileReader:文件字符输入流
共性的成员方法:
read() 读取单个字符并返回。
read(char[] cbuf)一次读取多个字符,将字符读入数组。
close() 关闭该流并释放与之关联的所有资源。
4,FileWriter:文件字符输出流
共性的成员方法:
write(int c) 写入单个字符。
write(char[] cbuf)写入字符数组。
write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
write(String str)写入字符串。
write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
flush()刷新该流的缓冲。
close() 关闭此流,但要先刷新它。
flush方法和close方法的区别
- flush :刷新缓冲区,流对象可以继续使用。
- close: 先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
字符输出流写数据的其他方法
write(char[] cbuf)写入字符数组。
write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
write(String str)写入字符串。
write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
5,try catch finally
JDK7的新特性
在try的后边可以增加一个(),在括号中可以定义流对象
那么这个流对象的作用域就在try中有效
try中的代码执行完毕,会自动把流对象释放,不用写finally
格式:
try(定义流对象;定义流对象....){
可能会产出异常的代码
}catch(异常类变量 变量名){
异常的处理逻辑
6, Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。
Properties集合是一个唯一和IO流相结合的集合
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
属性列表中每个键及其对应值都是一个字符串。
Properties集合是一个双列集合,key和value默认都是字符串
使用Properties集合存储数据,遍历取出Properties集合中的数据
Properties集合是一个双列集合,key和value默认都是字符串
Properties集合有一些操作字符串的特有方法
setProperty(String key, String value) 调用 Hashtable 的方法 put。
getProperty(String key) 通过key找到value值,此方法相当于Map集合中的get(key)方法
Set<String> stringPropertyNames() 返回此属性列表中的键集,其中该键及其对应值是字符串,此方法相当于Map集合中的keySet方法
tips1:
可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
参数:
OutputStream out:字节输出流,不能写入中文
Writer writer:字符输出流,可以写中文
String comments:注释,用来解释说明保存的文件是做什么用的
不能使用中文,会产生乱码,默认是Unicode编码
一般使用""空字符串
使用步骤:
1.创建Properties集合对象,添加数据
2.创建字节输出流/字符输出流对象,构造方法中绑定要输出的目的地
3.使用Properties集合中的方法store,把集合中的临时数据,持久化写入到硬盘中存储
4.释放资源
ex:prop.store(new FileOutputStream("09_IOAndProperties\\prop2.txt"),"");
tips2:
可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
void load(InputStream inStream)
void load(Reader reader)
参数:
InputStream inStream:字节输入流,不能读取含有中文的键值对
Reader reader:字符输入流,能读取含有中文的键值对
使用步骤:
1.创建Properties集合对象
2.使用Properties集合对象中的方法load读取保存键值对的文件
3.遍历Properties集合
注意:
1.存储键值对的文件中,键与值默认的连接符号可以使用=,空格(其他符号)
2.存储键值对的文件中,可以使用#进行注释,被注释的键值对不会再被读取
3.存储键值对的文件中,键与值默认都是字符串,不用再加引号
1,BufferedOutputStream:字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("10_IO\\a.txt"));
2, BufferedInputStream:字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("10_IO\\a.txt"));
3,BufferedWriter:字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("10_IO\\c.txt"));
特有的成员方法:
void newLine() 写入一个行分隔符。会根据不同的操作系统,获取不同的行分隔符
4,BufferedReader:字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("10_IO\\c.txt"));
特有的成员方法:
String readLine() 读取一个文本行。读取一行数据
行的终止符号:通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或回车后直接跟着换行(\r\n)。
5,OutputStreamWriter: 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。(编码:把能看懂的变成看不懂)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("10_IO\\gbk.txt"),"GBK");
不指定默认使用UTF-8
6, InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。(解码:把看不懂的变成能看懂的)
InputStreamReader isr = new InputStreamReader(new FileInputStream("10_IO\\gbk.txt"),"GBK");
7, ObjectOutputStream:对象的序列化流
作用:把对象以流的方式写入到文件中保存
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("10_IO\\person.txt"));
使用ObjectOutputStream对象中的方法writeObject,把对象写入到文件中
oos.writeObject(new Person("小美女",18));
8,ObjectInputStream:对象的反序列化流
作用:把文件中保存的对象,以流的方式读取出来使用
readObject方法声明抛出了ClassNotFoundException(class文件找不到异常)
当不存在对象的class文件时抛出此异常
反序列化的前提:
1.类必须实现Serializable
2.必须存在类对应的class文件
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("10_IO\\person.txt"));
使用ObjectInputStream对象中的方法readObject读取保存对象的文件
Object o = ois.readObject();
释放资源
ois.close();
使用读取出来的对象(打印)
System.out.println(o);
Person p = (Person)o;
9, PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
PrintStream特点:
1.只负责数据的输出,不负责数据的读取
2.与其他输出流不同,PrintStream 永远不会抛出 IOException
3.有特有的方法,print,println
void print(任意类型的值)
void println(任意类型的值并换行)
注意:
如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97
PrintStream ps = new PrintStream("10_IO\\print.txt");
//如果使用继承自父类的write方法写数据,那么查看数据的时候会查询编码表 97->a
ps.write(97);
//如果使用自己特有的方法print/println方法写数据,写的数据原样输出 97->97
ps.println(97);
使用System.setOut方法改变输出语句的目的地改为参数中传递的打印流的目的地
static void setOut(PrintStream out)
重新分配“标准”输出流。
=====================================
System.out.println("我是在控制台输出");
PrintStream ps = new PrintStream("10_IO\\目的地是打印流.txt");
System.setOut(ps);//把输出语句的目的地改变为打印流的目的地
System.out.println("我在打印流的目的地中输出");
1,软件结构:
c/s结构:客户端和服务器结构
b/s结构:浏览器和服务器结构
2,网络通信协议:
TCP:传输控制协议。需连接服务器(三次握手,保证传输的可靠性)
UDP:面向无连接的协议,传输速度快,有可能会丢包
3,编程三要素:
协议 IP地址 端口号
4,Socket类
Socket socket = new Socket("127.0.0.1",8888);
网络字节流(传输):OutputStream os = socket.getOutputStream();
5,ServerSocket类
ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
6,文件上传案例的客户端:读取本地文件,上传到服务器,读取服务器回写的数据
void shutdownOutput() 禁用此套接字的输出流。
对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。
7,文件上传案例服务器端:读取客户端上传的文件,保存到服务器的硬盘,给客户端回写"上传成功"
让服务器一直处于监听状态(死循环accept方法)
有一个客户端上传文件,就保存一个文件
使用多线程技术,提高程序的效率
有一个客户端上传文件,就开启一个线程,完成文件的上传
自定义一个文件的命名规则:防止同名的文件被覆盖
规则:域名+毫秒值+随机数
7, 创建BS版本TCP服务器
把is网络字节输入流对象,转换为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
把客户端请求信息的第一行读取出来
|
|