Java语法
Java基础语法
IO流
一、File类
/*
java.io.File 文件类 提供了用于操作文件 创建文件 获取文件信息等 各种文件相关的方法
exists() 判断文件或目录是否存在
boolean isFile() 判断是否是文件
boolean isDirectory() 判断是否是目录
String getPath() 返回此对象表示的文件的绝对路径名
String getAbsolutePath() 返回此对象表示的文件的绝对路径名
String getName() 返回此对象表示的文件或目录的名称
boolean delete() 删除此对象指定的文件或目录
boolean createNewFile() 创建名称的空文件,不创建文件夹
long length() 返回文件的长度,单位为字节,如果文件不存在,则返回Ol*/
public class TestFile {public static void main(String[] args){File file1 = new File("C:/Users/YY/Desktop/0628.txt");System.out.println("文件是否存在" + file1.exists());System.out.println("是否为一个文件" + file1.isFile());System.out.println("是否为一个文件夹" + file1.isDirectory());System.out.println("获取文件绝对路径" + file1.getPath());System.out.println("获取文件绝对路径" + file1.getAbsolutePath());System.out.println("获取文件名称" + file1.getName());System.out.println("获取文件大小,单位为字节:" + file1.length());System.out.println("删除文件" + file1.delete());System.out.println("-------------------------------------");File file2 = new File("D://a.txt");System.out.println("创建文件是否成功" + file2.createNewFile());System.out.println("文件是否可操作:" + file2.canExecute());System.out.println("文件是否可写:" + file2.canWrite());System.out.println("文件是否可读:" + file2.canRead());System.out.println("是否为隐藏文件:" + file2.isHidden());long lastModified = file2.lastModified();Date date = new Date(lastModified);System.out.println("最后一次修改时间:" + date);System.out.println("删除文件:" + file2.delete());System.out.println("文件是否存在:" + file2.exists());System.out.println("------------------------------------------");File file3 = new File("D://A");System.out.println("创建文件夹:" + file3.mkdir());System.out.println("------------------------------------------");}
}
二、字节流
字节读取流
输入是读取数据,输出是写数据
InputStream流-读
FileInputStream
/*
InputStream 字节读取流父类 抽象类
FileInputStreamread() : 每次读取一个字节 返回值为读取的内容 ASCII码 如果读取到文件的末尾 返回值为-1
read(byte[] data): 每次读取一个字节数组 返回值为读取字节的个数 读取的内容保存在byte数组中 如果读取到文件的末尾 返回值为-1
available() 返回当前字节流可读字节数
close() 关闭字节流*/
public class TestFileInputStream1 {public static void main(String[] args){// 使用相对路径创建File对象File file = new File("A.txt");FileInputStream inputStream = null;try{// 创建字节读取流对象 参数为file对象inputStream = new FileInputStream(file);// 读取文件 读取一个字节int readData = inputStream.read();// 打印 因为读取内容的返回值为int类型 所以需要强转为char类型System.out.println("readData = " + (char)readData);// 读取文件 读取一个字节readData = inputStream.read();System.out.println("readData = " + (char)readData);// 使用循环多次读取内容的返回值为int类型 所以需要强转为char类型while((readData = inputStream.read()) != -1){System.out.println((char)readData); // 强制类型转换}}catch (FileNotFoundException e){e.printStackTrace();}catch (IOException e){throw new RuntimeException(e);}finally{// 做非null判断if(inputStream != null){try{inputStream.close(); // 关闭资源}catch (IOException e){e.printStackTrace();}} }}
}
/*
read(byte[] data):每次读取一个字节数组 返回值为读取字节的个数 读取的内容保存在byte数组中
如果读取到文件的末尾 返回值为-1
*/
public class TestFileInputStream2{public static void main(String[] args) throws IOException {FileInputStream inputStream = new FileInputStream("A.txt");// 定义数组 长度为15 表示每次读取15个字节byte[] data = new byte[15];// 定义变量表示实际读取的字节的个数int readCount = -1;// 循环读取 每次读取到的内容保存在byte数组中 读取到的个数 保存在 readCount中while((readCount = inputStream.read(data)) != -1){// 解析byte数组 转换为字符串// 第一个参数 byte数组// 第二个参数 从0开始转换// 第三个参数 转换的数量(即读取到几个 就转换几个字节)System.out.println(new String(data,0,readCount));}inputStream.close();System.out.println("程序结束");}
}
/*
使用字节流读取中文
available() 返回当前字节流可读字节数
中文占几个字节?UTF-8 占3个字节GBK 占2个字节
*/
public class TestFileInputStream3 {public static void main(String[] args){FileInputStream inputStream = null;try{inputStream = new FileInputStream("A.txt");int available = inputStream.available();System.out.println("可读字节数 = " + available);// 使用可读字节数来定义数组长度 避免拆分中文 导致乱码byte[] data = new byte[inputStream.available()];int readCount = -1;while((readCount = inputStream.read(data)) != -1){System.out.println(new String(data,0,readCount));}}catch(FileNotFoundException e){e.printStackTrace();}catch(IOException e){e.printStackTrace();}finally{inputStream.close();// 关闭资源}}
}
OutputStream写
FileOutputStream
/*
OutputStream
FileOutputStreamnew FileOutputStream(String fileName) 传入字符串
new FileOutputStream(File file) 传入文件对象
new FileOutputStream(File file,boolean append) true表示追加 默认不写 或者 false 表示覆盖源文件使用字节写入流写入文件 如果文件不存在 则自动创建write(int data) 写入单个字节
write(byte[] data) 写入字节数组
close() 关闭写入字节流*/
public class TestFileOutputStream1 {public static void main(String[] args){FileOutputStream outputStream = null;try {outputStream = new FileOutputStream("B.txt");outputStream.write(65);outputStream.write(66);outputStream.write(67);outputStream.write(68);outputStream.write(69);} catch (FileNotFoundException e){e.printStackTrace();} catch (IOException e){e.printStackTrace();}finally{if(outputStream != null){try{outputStream.close();} catch (IOException e){throw new RuntimeException(e);}}}}
}
/*
write(byte[] data) 写入字节数据
*/
public class TestFileOutputStream2 {public static void main(String[] args) throws IOException{FileOutputStream outputStream = new FileOutputStream("C.txt",true); // true表示继续追加byte[] data = {97,98,99,100};outputStream.write(data);outputStream.close();}
}
字节写入流
/*
使用字节写入流写入中文
*/
public class TestFileOutputStream3 {public static void main(String[] args) throws IOException {FileOutputStream outputStream = new FileOutputStream("D.txt",true);String str = "世界你好 hello world 666";byte[] bytes = str.getBytes();outputStream.write(bytes);outputStream.close();}
}
三、字符流
Reader字符读取流
InputStreamReader
/*
Reader 字符读取流 父类 抽象类
InputStreamReaderread() 每次读取一个字符 返回值为读取的内容 如果读取到文件末尾 返回数为-1
close() 关闭资源
*/
public class TestInputStreamReader {public static void main(String[] args){FileInputStream fileInputStream = null;InputStreamReader reader = null;try{fileInputStream = new FileInputStream("A.txt");reader = new InputStreamReader(fileInputStream);int data = reader.read();System.out.println((char)data);data = reader.read();System.out.println((char)data);while((data = reader.read()) != -1){System.out.println((char)data);}}catch(FileNotFoundException e){throw new RuntimeException(e); }catch(IOException e){e.printStrace();}finally{// 关闭资源 先用后关 try{if(reader != null){reader.close();}if(fileInputStream != null){fileInputStream.close();}}catch(IOException e){e.printStackTrace();}}}
}
/*
read(char[] data)每次读取一个字符数组 返回值为读取字符的个数 读取的内容保存在数组中 读取到末尾 返回值为-1
*/
public class TestInputStreamReader2{public static void main(String[] args) throws IOException{InputStreamReader reader = new InputStreamReader(new FileInputStream("A.txt"));char[] data = new char[5];int readCount = -1;while((readCount = reader.read(data)) != -1){System.out.println(data);// 将字符数组 转换为String对象// 第一个参数为要转换的字符数组// 第二个参数为0 表示从数组中的第一个位置开始转换// 第三个参数 为转换的个数 readCount表示读取了多少 就转换多少System.out.println(new String(data,0,readCount));}byte[] b = {1,2,3,4,5};System.out.println("b = " + b);char[] c = {'a','b','c'};System.out.println("c = " + c); // println方法单独对char数组作为参数 做了操作 直接遍历 拼接 再 打印}
}
/*
使用InputStreamReader解决读取中文乱码问题如果文件的编码格式 和 本地平台默认读取文件的编码格式不一致
将产生乱码 可以使用InputStreamReader类构造方法 传入 编码格式 来指定编码*/
public class TestInputStreamStreamReader3{public static void main(String[] args) throws IOException{FileInputStream fileInputStream = new FileInputStream("a.txt");InputStream fileInputStream = new InputStreamReader(fileInputStream,"666");char[] data = new char[10];}
}
FileReader
/*
Reader
InputStreamReader
FileReader: 只能按照本地平台默认的编码格式读取数据 不能单独指定数read() 每次读取一个字符 返回值为读取内容的ASCII码 或者 Unicode编码 十进制 如果读取到末尾 返回-1
read(char[] data) 每次读取一个字符数组 返回值为读取字符的个数 如果读取到末尾 返回-1
close() 关闭资源*/
public class TestFileReader1 {public static void main(String[] args){// 定义FileReader对象FileReader fileReader = null;try{// 创建对象 并且指定读取文件 fileReader = new FileReader("A.txt");// 调用read()方法 读取一个字符 接收返回值int readData = fileReader.read();// 打印读取数据 返回值为int类型 需要强转为char类型System.out.println("readData = " + (char)readData);readData = fileReader.read();System.out.println("readData = " + (char)readData);// 循环读取 循环依据为读取返回值不为-1 表示还未读取结束while((readData = fileReader.read()) != -1){System.out.println("readData = " + (char)readData);}}catch(FileNotFoundException e){e.printStackTrace();}catch(IOException e){e.printStackTrace();}finally{// 关闭资源try{if(fileReader != null){fileReader.close();}}catch(IOException e){e.printStackTrace();}}}
}
/*
read(char[] data) 每次读取一个字符数组 返回值为读取字符的个数 如果读取到末尾 返回-1
*/
public class TestFileReader2 {public static void main(String[] args) throws IOException {// 创建对象 并且指定读取文件FileReader reader = new FileReader("A.txt");// 创建长度为10的char数组 用于保存读取数据char[] data = new char[10];// 定义每次读取的个数 初始化值为-1int readCount = -1;// 循环读取 循环条件为 读取字符个数不为-1while((readCount = reader.read(data)) != -1){// 读取完毕的字符数组 转换为字符串// 第一个参数 为字符数组// 第二个参数 转换为字符串的起始位置// 第三个参数 转换个数System.out.println(new String(data,0,readCount));}reader.close();}
}
BufferedReader
/*
Reader
BufferedReader 带有缓冲区的字符读取流 也叫缓冲流 可以提高读取文件的效率
因为读取过程是先将内容 读取到内存 等待一行读取完毕 再一次性加载到程序中 相当于减少了与温度 内存 IO的次数 所以效率更高String readLine() 每次读取一行内容
*/
public class TestBufferedReader1 {public static void main(String[] args){// 声明字节流对象FileInputStream fileInputStream = null;// 声明字符流/转换流 对象InputStreamReader inputStreamReader = null;// 声明字符流对象BufferedReader reader = null;try{// 指定读取文件fileInputStream = new FileInputStream("A.txt"); // 有无参构造// 创建转换流对象 需要使用字符流对象作为参数inputStreamReader = new InputStreamReader(fileInputStream);// 传入参数 转换流// 创建缓冲流对象 使用转换流作为参数reader = new BufferedReader(inputStreamReader);// 这时候创建对象才完毕// 声明读取内容返回值 因为每次读取一行 所以返回值为String类型String line = null;// 循环读取 循环依据为返回值不为空 表示还未读取完毕while((line = reader.readLine()) != null){System.out.println(line); // 打印读取内容}}catch (FileNotFoundException e){throw new RuntimeException(e);}catch (IOException e){e.printStackTrace();}finally{// 关闭资源 先用后关// 关闭之前做非空判断try{if(reader != null){reader.close();}if(inputStreamReader != null){inputStreamReader.close();}if(fileInputStream != null){fileInputStream.close();}} catch (IOException e){e.printStackTrace(); // 打印堆栈信息}}}
}
OutputStreamWrite
public class A {public static void main(String[] args){try{System.out.println(10 / 0);}catch (Exception e){// throw new RuntimeException(e); 抛出异常中断程序e.printStackTrace(); // 打印堆栈信息 程序继续执行}System.out.println("程序结束");}
}
Writer
/*
Writer 字符写入流 父类 抽象类
OutputStreamWriter 写入的转换流
OutputStreamWriter(OutputStream)
OutputStreamWriter(OutputStream,String charSetName)write(String str): 写入内容 直接写入字符串
flush() 刷新内容 将内存中的内容刷新到硬盘中
close() 关闭资源
*/
public class TestOutputStreamWriter1 {public static void main(String[] args){// 声明字节写入流对象FileOutputStream fileOutputStream = null;// 声明字符写入流/转换流 对象OutputStreamWriter writer = null;try {// 创建字节写入流对象// 第一个参数 表示写入当前相对路径下(相对于当前项目而言的路径)A.txt 如果文件不存在,将自动创建// 第二个参数 true 表示在原文件基础之上追加内容 false 或者不写 表示覆盖原内容fileOutputStream = new FileOutputStream("A.txt",true); // true表示是否追加// 创建字符写入流 / 转换流对象 使用字节流对象作为参数构造实例writer = new OutputStreamWriter();// 写入文件writer.write("世界你好 hello world 666");}catch (FileNotFoundException e){e.printStackTrace();}catch (IOException e){e.printStackTrace();}finally{// 关闭资源try{if(writer != null){writer.close();}if(fileOutputStream != null){fileOutputStream.close();}}catch(IOException e){e.printStackTrace();}}}
}
/*
OutputStreamWriter(OutputStream,String charSetName) 指定写入文件的编码格式
*/
public class TestOutputStreamWriter2 {public static void main(String[] args) throws IOException {// 打印本地平台默认的编码格式System.out.println(System.getProperty("file.encoding")); // 创建字节流对象 如果文件不存在将自动创建FileOutputStream fileOutputStream = new FileOutputStream("c.txt");// 创建字符流/转换流 对象 指定写入文件编码格式为 'GBK'OutputStreamWriter writer = new OutputStreamWriter(fileOutputStream,"GBK");// 写入文件writer.write("hello world 世界你好 666");// 刷新缓存writer.flush();writer.close();// 关闭资源FileInputStream fileInputStream = new FileInputStream("c.txt");// 因为写入的编码格式为 GBK 所以读取的编码格式也应该设置为 GBK 否则将出现乱码InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"GBK");BufferedReader reader = new BufferedReader(inputStreamReader);System.out.println(reader.readLine());reader.close();inputStreamReader.close();fileInputStream.close();writer.close();fileOutputStream.close();}
}
FileWriter
/*
Writer
OutputStreamWriter
FileWriter: 只能按照本地平台默认的编码格式写入文件
*/
public class TestFileWriter {public static void main(String[] args){// 声明写入文件对象FileWriter writer = null;try{// 创建对象 并且指定写入文件 如果文件不存在 将会自动创建// 默认不写第二个参数 表示覆盖原文件内容writer = new FileWriter("D.txt");// 写入内容writer.writer("hello world 世界你好 666");writer.flush(); // 刷新缓存}catch (IOException e){e.printStackTrace();}finally{// 关闭资源try {if(writer != null){writer.close();}}catch(IOException e){e.printStackTrace();}}}
}
BufferedWriter
/*
BufferedWriter: 带有缓冲区的字符写入流 写入的内容先保存在缓冲区 调用 flush方法 将缓冲区中的内容*/
public class TestBufferedWriter {public static void main(String[] args) throws IOException {// 创建对象 以匿名对象的方式作为参数构造实例BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("E.txt")));// 写入文件 \n 和 newLine() 方法 都可以实现换行的效果writer.writer("hello world \n 世界你好 \n 666 1");writer.newLine();writer.write("hello world \n 世界你好 \n 666 2");writer.flush(); // 刷新缓存writer.close(); // 关闭资源}
}
DataStream
/*
数据流 按照单元划分 属于字节流
DataInputStream 负责读取二进制文件
read(byte[] data) :每次读取一个byte数组DataOutputStream 负责写入二进制文件
write(byte[] data):写入byte数组
*/
public class TestDataStream{public static void main(String[] args) throws FileNotFoundException {// 定义字节读取流对象 表示读取此文件FileInputStream fileInputStream = new FileInputStream(1.jpg);// 定义数据写入流对象 将字节流对象转入 作为参数 构造实例DataInputStream dataInputStream = new DataInputStream(fileInputStream);// 定义byte数组 长度为此文件的可读字节数byte[] data = new byte[fileInputStream.available()];// 读取文件 内容保存在byte数组中dataInputStream.read(data);System.out.println(new String(data,0,data,length));// 定义写入文件字节流对象 指定写入文件位置 以及 名称FileOutputStream fileOutputStream = new FileOutputStream("girl.jpg");// 定义数据写入流对象 将字节写入流对象作为参数 构造实例DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);// 写入文件dataOutputStream.write(data);}
}
ObjectStream
/*
序列化和反序列化:序列化是指将对象保存在二进制文件中反序列化是指将保存有对象的二进制文件读取出来 生成新的对象被序列化的对象 所属的类必须实现序列化接口 Serializable接口Serializable接口时一个空接口 只是相当于一个标识 表示此类可以被序列化ObjectInputStream 负责读取对象
readObject() 返回值为Object类型的对象ObjectOutputStream 负责写入对象
writeObject() 返回值类型为void
static
*/
public class TestObjectStream{public static void main(String[] args) throws IOException {Student stu1 = new Student("赵四1",21,'男');Student stu2 = new Student("赵四2",22,'男');Student stu3 = new Student("赵四3",23,'男');// 创建字节流对象 指定写入文件FileOutputStream fileOutputStream = new FileOutputStream("student.txt");// 创建对象流对象 使用字节流对象作为参数构造实例ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);// 写入对象objectOutputStream.writeObject(stu1);objectOutputStream.writeObject(stu2);objectOutputStream.writeObject(stu3);System.out.println("----------------------------------------------");// 反序列化// 创建对象 指定读取文件FileInputStream fileInputStream = new FileInputStream(student.txt);// 创建对象 使用字节流对象作为参数 构造实例ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);Object o1 = objectInputStream.readObject();// 第一种方式System.out.println(o1);Object o2 = objectInputStream.readObject();// 第二种方式if(o2 instanceof Student){Student stu = (Student) o2;System.out.println(stu.getName());System.out.println(stu.getAge());System.out.println(stu.getSex());}Object o3 = objectInputStream.readObject();System.out.println(o3);// 第三种方式 判断可读字节数 大于0 表示文件中还有内容 继续读取while(fileInputStream.available() > 0){Object o = objectInputStream.readObject(); // 每次读取一个对象System.out.println("o = " + o);// 打印}}
}
/*
如果不希望某个属性被序列化 可以使用transient(瞬间) 关键字修饰
*/
public class Student implements Serializable {private String name;private transient int age; // 瞬时的private char sex;public Student(){}public Student(String name,int age,char sex){this.name = name;this.age = age;this.sex = sex;}@Overridepublic String toString(){return "Student{" + "name'" + name + '\'' + ",age=" + age + ",sex=" + sex +'}';}public String getName(){return name;}public void setName(String name){this.name = name;}public int getAge(){return age;}public void setAge(int age){this.age = age;}public char getSex(){return sex;}public void setSex(char sex){this.sex = sex;}
}
线程相关概念
多线程
1.程序一系列代码指令的集合统称,应用,软件等等 都属于程序程序必须依托于进程而存在,进程负责分配资源,依赖线程来进行
2.进程进程进行中应用程序 属于资源分配的基本单位
3.线程线程是包含在进程之中的一个进程至少有一个线程 否则将无法运行 线程是CPU调度运算的基本单位4.关于线程开辟和线程执行线程不是越多越好 要结合实际的硬件环境来决定的在单核心CPU下,多线程是轮流交替执行的 以windows操作系统为例 多个线程轮流交替执行 每个线程最多执行20ms 继续切换下一个线程 而非执行 因为切换的频率非常快 所以我们感知不到这个线程 宏观上是同时执行的 实际上是轮流交替执行的5.并发和并行并发:同时发生,但是轮流交替进行 宏观同时执行 微观轮流交替执行并行:严格意义上的同时进行
主线程
/*
main方法为程序的入口 底层由main线程负责执行 由JVM自动调用执行
java.lang.Thread 线程类currentThread() 获取当前线程对象 是一个静态方法
getName() 获取线程名称
setName(String name) 设置线程名称*/
public class TestMainThread {public static void main(String[] args){// 获取当前线程对象Thread thread = Thread.currentThread();System.out.println("线程的名称:" + thread.getName());// 设置线程名称thread.setName("主线程");// 打印线程名称System.out.println("线程的名称:" + thread.getName());}
}
创建线程的两种方式
/*
创建线程方式1:继承Thread类 重写run方法创建的子线程如果没有指定名称 将默认以 Thread-0 -1 这种方式来命名
*/
public class MyThread1 extends Thread{@Overridepublic void run(){for(int i = 1;i <= 20;i++){System.out.println(Thread.currentThread().getName() + "===" + i);}}public static void main(String[] args){MyThred1 th1 = new MyThread1();MyThred1 th2 = new MyThread1();th1.start();th2.start();}
}
/*
创建线程方式2:实现Runnable接口 重写run方法 Runnable实现类可以作为参数构造Thread实例继承Thread和实现Runnable接口的区别?继承Thread类 编写简单,可直接操作线程 适用于单继承实现Runnable接口 避免单继承局限性 便于共享资源调用 start方法和run方法的区别?
调用start方法表示通知调度器(CPU)当前线程准备就绪 调度器会开启新的线程来执行任务
调用run方法表示使用当前主线程来执行方法 不会开启新的线程
*/
public class MyThread2 implements Runnable{@Overridepublic void run(){for(int i = 1;i <= 20;i++){System.out.println(Thread.currentThread().getName() + "---" + i);}}public static void main(String[] args){// 创建Runnable实现类对象RunnableImpl runnable = new RunnableImpl();// 使用 Runnable实现类对象构造Thread对象 定义线程名为 '线程A'Thread th1 = new Thread(runnable,"线程A");// 使用 Runnable实现类对象构造Thread对象Thread th2 = new Thread(runnable);// 重新设置线程名th2.setName("*****线程B*****");// 运行线程th1.start();th2.start();}}
线程的状态
/*
线程状态:创建 就绪 运行 阻塞 死亡
*/
public class TestThreadStatus extends Thread{@Overridepublic void run(){// 运行try{Thread.sleep(3000); // 阻塞状态}catch(InterruptedException e){e.printStackTrace();}System.out.println("当前线程名称" + Thread.currentThread().getName());System.out.println("线程执行完毕");// 死亡}public static void main(String[] args){// 创建TestThreadStatus threadStatus = new TestThreadStatus();// 就绪threadStatus.start();}
}
线程的优先级
/*
线程的优先级:从1~10 1最低 10最高 默认为5 优先级高的线程只是获得CPU资源的概率较大 并不一定能够保证优先执行*/
public class TestPriority{@Overridepublic void run(){for(int i = 1;i <= 20;i++){System.out.println(Thread.currentThread().getName() + "---" + i); }}public static void main(String[] args){TestPriority th1 = new TestPriority();th1.setName("线程A");TestPriority th2 = new TestPriority();th2.setName("****线程B****");// 设置线程优先级th1.setPriority(Thread.MAX_PRIORITY); // 10 NORM_PRIORITY-5 MIN_PRIORITY-1System.out.println("线程A优先级" + th1.getPriority());System.out.println("线程B优先级" + th2.getPriority());th1.start();th2.start();}
}
线程的休眠
/*
线程的休眠:
sleep(long millis) 让当前线程等待指定时间 然后再继续执行
*/
public class TestSleep extends Thread{@Overridepublic void run(){System.out.println(Thread.currentThread().getName() + "线程开始执行");try{// 因为父类run方法没有声明任何异常 所以子类也不能声明任何异常Thread.sleep(3000); // 休眠3秒钟 到达时间 自动继续执行}catch(InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "线程执行完毕");}public static void main(String[] args){TestSleep thread = new TestSleep();thread.start();}
}
线程的插队
/*
线程的插队
join() 当前线程插队 直到插队线程执行完毕
join(long millis) 线程插队 插队指定的时间
join(long millis,int nanos) 线程插队 插队指定的时间*/
public class TestJoin extends Thread{@Overridepublic void run(){for(int i = 1;i <= 20;i++){System.out.println(Thread.currentThread().getName() + "---" + i);}}public static void main(String[] args) throws InterruptedException {TestJoin thread = new TestJoin();thread.setName("***线程A***");thread.start();for(int i = 1;i <= 50; i++){// 当i取值为10 子线程插队if(i == 10){System.out.println("子线程插队");thread.join(500); // 插队指定时间为500毫秒}System.out.println(Thread.currentThread().getName() + "===" + i);}}
}
线程的礼让
/*
线程的礼让
yield() 当前线程向调度器发出信息 表示当前正在执行的线程愿意做出让步 但是调度器可以忽略这个信息
*/
public class TestYield extends Thread {@Overridepublic void run(){for(int i = 1;i <= 20;i++){try{Thread.sleep(200);}catch(InterruptedException e){e.printStackTrace();}if(i == 10){ // 当i取值为10 则礼让 但不保证一定会礼让成功System.out.println(Thread.currentThread().getName + "线程礼让了");Thread.yield(); // 线程礼让}System.out.println(Thread.currentThread().getName() + "---" + i);}}public static void main(String[] args){TestYield th1 = new TestYield();TestYield th2 = new TestYield();th1.setName("线程A");th2.setName("****线程B****");th1.start();th2.start();}
}
课堂练习
/*
模拟多人爬山
分析:将run方法体的内容 作为两个角色共同执行的爬山过程 爬山的速度不一样 所以表示休眠的时间不同
爬山的高度是相同的 角色名称不同 表示线程名不同 同时创建两个线程对象 分别start方法 表示开始
同时爬山 因为爬山速度不同 所以到达山顶时间是不同的
*/
public class ClimbThread extends Thread{private int length; // 高度private int time; // 每爬100米耗时private String name; // 角色名 线程名public ClimbThread(int length,int time,String name){super(name);this.length = length;this.time = time;}@Overridepublic void run(){while(length > 0){try {Thread.sleep(time);} catch(InterruptedException e){e.printStackTrace();}length -= 100;System.out.println(Thread.currentThread().getName() + "爬了100米,还剩余" + length + "米");}System.out.println(Thread.currentThread().getName() + "爬到了山顶");}public static void main(String[] args){ClimbThread youngMan = new ClimbThread(1000,500,"练习两年半的年轻人");ClimbThread oldMan = new ClimbThread(1000,1000,"马老师");youngMan.start();oldMan.start();}
}
/*
某科室一天需看普通号50个,特需号10个(执行不同的次数)
特需号看病时间是普通号的2倍(休眠时间)
开始时普通号和特需号并行叫号,叫到特需号的概率比普通号高(同时start开始执行 优先级不同)
当普通号叫完第10号时,要求先看完全部特需号,再看普通号(插队)
使用多线程模拟这一过程分析:子线程作为特需号类 主线程作为普通号类
*/
public class Special extends Thread{@Overridepublic void run(){for(int i = 1;i <= 10;i++){try{Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "第" + i + "号在看病");System.out.println(System.out.println(Thread.currentThread().getName() + "看病完毕");}public static void main(String[] args) throws InterruptedException{Special special = new Special();special.setName("*****特需号*****");special.setPriority(MAX_PRIORITY);special.start();Thread mainThread = Thread.currentThread();mainThread.setName("普通号");for(int i = 1;i <= 50;i++){Thread.sleep(500);System.out.println(Thread.currentThread().getName() + "第" + i + "号在看病");if(i == 10){special.join();}}System.out.println(Thread.currentThread().getName() + "看病完毕");}}
}
同步关键字
/*
使用多线程模拟:多人抢票 三个人 抢10张票分析问题:目前使用多个线程抢10张票 属于一个数据被多个线程共享
因为多个线程之间没有先后顺序的规则 所以没有相互制约的效果 所以会导致
票重复卖出 以及 超卖的问题解决方案:多个线程必须排队买票 保证同一时间只能有一个线程买票 前面的线程购买完毕 后面的线程才可以继续购买
*/
public class BuyTicket1 extends Thread{static int ticketCount = 10;@Overridepublic void run(){while(ticketCount > 0){try {Thread.sleep(1000);}catch (InterruptedException e){e.printStackTrace();}ticketCount--;System.out.println(Thread.currentThread().getName() + "抢到了第" + (10-ticketCount) + "张票,还剩余+ "ticketCount" +张票");}System.out.println("票卖完了");}public static void main(String[] args){BuyTicket1 zs = new BuyTicket1();zs.setName("赵四");BuyTicket1 gk = new BuyTicket1();gk.setName("广坤");BuyTicket1 dn = new BuyTicket1();dn.setName("大拿");zs.start();gk.start();dn.start();}
}
/*
使用多线程模拟:多人抢票 三个人 抢10张票
有一个线程买票 前面的线程购买完毕 后面的线程才能继续购买同步关键字:synchronized
可以用于修饰方法 和 代码块 ,分别表示同一时间只能有一个线程访问这个方法 或者 这个代码块
*/
public class BuyTicket2 implements Runnable{int ticketCount = 10;@Overridepublic void run(){while(true){try{Thread.sleep(500);}catch(InterruptedException e){e.printStackTrace();}synchronized (this){if(ticketCount == 0){break;}ticketCount--;System.out.println(Thread.currentThread().getName() + "抢到了第" + (10-ticketCount) + "张票,还剩余+ "ticketCount" +张票");}}System.out.println("票卖完了");}public static void main(String[] args){BuyTicket2 runnable = new BuyTicket2();Thread th1 = new Thread(runnable,"赵四");Thread th2 = new Thread(runnable,"广坤");Thread th3 = new Thread(runnable,"大拿");th1.start();th2.start();th3.start();}}
}
/*
同步方法
*/
public class BuyTicket3 implements Runnable{int ticketCount = 10;// 表示同步方法@Overridepublic synchronized void run(){while(true){try{Thread.sleep(500);}catch(InterruptedException e){e.printStackTrace();}while(ticketCount > 0){ticketCount--;System.out.println(Thread.currentThread().getName() + "抢到了第" + (10-ticketCount) + "张票,还剩余+ "ticketCount" +张票");}System.out.println("票卖完了");}public static void main(String[] args){BuyTicket2 runnable = new BuyTicket2();Thread th1 = new Thread(runnable,"赵四");Thread th2 = new Thread(runnable,"广坤");Thread th3 = new Thread(runnable,"大拿");th1.start();th2.start();th3.start();}}
}
同步关键字总结
/*
使用多线程模拟:多人抢票 三个人 抢10张票
有一个线程买票 前面的线程购买完毕 后面的线程才能继续购买同步关键字:synchronized关于同步代码块中的this关键字 this表示当前对象 即Runnable实现类对象
同步代码块小括号中可以写任何对象 如果需要实现多个线程同步的效果
则必须保证 多个线程所使用 锁定的 是同一个对象 负责 将不能实现线程同步
通常书写为this
*/
public class BuyTicket2 implements Runnable{int ticketCount = 10;Object obj = new Object();@Overridepublic void run(){while(true){try{Thread.sleep(500);}catch(InterruptedException e){e.printStackTrace();}synchronized (obj){if(ticketCount == 0){break;}ticketCount--;System.out.println(Thread.currentThread().getName() + "抢到了第" + (10-ticketCount) + "张票,还剩余+ "ticketCount" +张票");}}System.out.println("票卖完了");}public static void main(String[] args){BuyTicket2 runnable = new BuyTicket2();Thread th1 = new Thread(runnable,"赵四");Thread th2 = new Thread(runnable,"广坤");Thread th3 = new Thread(runnable,"大拿");th1.start();th2.start();th3.start();}}
}
/*
多个并发线程访问同一资源的同步代码块时
同一时间只能有一个线程进入synchronized(this) 同步代码块
当一个线程访问一个synchronized(this) 同步代码块时,其他synchronized(this)同步代码块同样被锁定
当一个线程访问一个synchronized(this)同步代码块时,其他线程可以访问该资源的非synchronized(this)同步代码块我们之前接触到的线程安全的类 StringBuffer Vector Hashtable都是使用同步关键字修饰方法 实现的线程安全
*/
public class Test{public void m1(){synchronized(this){System.out.println("同步代码块1");}synchronzied(this){System.out.println("同步代码块2");}public static void main(String[] args){Thread thread = new Thread();}}
}
生产者消费者模式
/*
生产者消费者模式:不属于设计模式 属于线程之间通信的一种现象生产什么 消费什么
没有生产 不能消费(持续生产 持续消费)
必须保证产品的完整性
不能重复消费产品类Object类中的两个方法 : wait和notify方法
wait()方法 表示让当前线程等待
notify()方法:唤醒正在等待的线程
*/
public class Computer {public Computer(){}public Computer(String mainFrame,String screen){this.mainFrame = mainFrame;this.screen = screen;}private String mainFrame; // 主机private String screen; // 显示器private boolean flag; // 标识public boolean getFlag(){return flag;}public void setFlag(boolean flag){this.flag = flag;}public String getMainFrame(){return mainFrame;}public void setMainFrame(String mainFrame){this.mainFrame = mainFrame;}public String getScreen(){return screen;}public void setScreen(String screen){this.screen = screen;}@Overridepublic String toString(){return "Computer{"+ "mainFrame='" + mainFrame + '\'' + ",screen='" + screen + '\'' + '}';}}
/*
生产者线程 负责生产电脑
*/
public class Producer extends Thread{private Computer computer;public Producer(Computer computer){this.computer = computer;}@Overridepublic void run(){for(int i = 1;i <= 20;i++){synchronized (computer){if(computer.isFlag()){try {computer.wait();}catch(InterruptedException e){e.printStackTrace();}}if(i % 2 == 0){computer.setMainFrame(i + "号联想主机");computer.setScreen(i + "号联想显示器");System.out.println("生产了第" + i + "号联想电脑");}else{computer.setMainFrame(i + "号华硕主机");computer.setScreen(i + "号华硕显示器");System.out.println("生产了第" + i + "号华硕电脑");}computer.setFlag(true);// 消费者处于等待状态computer.notify();}}}
}
/*
消费者线程 负责消费电脑
*/
public class Consumer extends Thread{private Computer computer;public Consumer(Computer computer){this.computer = computer;}@Overridepublic void run(){for(int i = 1;i <= 20;i++){synchronized(computer){if(computer.isFlag() == false){try{computer.wait();}catch (IntegerruptedException e){e.printStackTrace();}}try{Thread.sleep(100);}catch(InterruptedException e){e.printStackTrace();}System.out.println(computer.getMainFrame() + "===" + computer.getScreen());computer.setFlag(false);}}}
}
public class Test{public static void main(String[] args){Computer computer = new computer();Producer producer = new Producer(computer);Consumer consumer = new Consumer(computer);producer.start();consumer.start();}
}
队列优先生产者消费者模式
/*
生产者消费者模式:不属于设计模式 属于线程之间通信的一种现象生产什么 消费什么
没有生产 不能消费(持续生产 持续消费)
必须保证产品的完整性
不能重复消费产品类ArrayBlockingQueue 基于数组的阻塞队列
队列 即FIFO First In First Out
阻塞表示队列是有长度限制的 所以当队列满了以后 将不能再添加新的数据到队列中add() 将数据存放在队列中
take() 从队列中取出数据*/
public class Computer {public Computer(){}public Computer(String mainFrame,String screen){this.mainFrame = mainFrame;this.screen = screen;}private String mainFrame; // 主机private String screen; // 显示器public String getMainFrame(){return mainFrame;}public void setMainFrame(String mainFrame){this.mainFrame = mainFrame;}public String getScreen(){return screen;}public void setScreen(String screen){this.screen = screen;}@Overridepublic String toString(){return "Computer{"+ "mainFrame='" + mainFrame + '\'' + ",screen='" + screen + '\'' + '}';}}
/*
生产者线程 负责生产电脑
*/
public class Producer extends Thread{private ArrayBlockingQueue<Computer> queue;public Producer(ArrayBlockingQueue<Computer> queue){this.queue = queue;}@Overridepublic void run(){for(int i = 1;i <= 20;i++){Computer computer = new Computer();if(i % 2 == 0){computer.setMainFrame(i + "号联想主机");computer.setScreen(i + "号联想显示器");System.out.println("生产了第" + i + "号联想电脑");queue.add(computer);}else{computer.setMainFrame(i + "号华硕主机");computer.setScreen(i + "号华硕显示器");System.out.println("生产了第" + i + "号华硕电脑");queue.add(computer);}}}
}
/*
消费者线程 负责消费电脑
*/
public class Consumer extends Thread{private ArrayBlockingQueue<Computer> queue;public Consumer(ArrayBlockingQueue<Computer> queue){this.queue = queue;}@Overridepublic void run(){for(int i = 1;i <= 20;i++){try{System.out.println(queue.take());}catch(InterruptedException e){e.printStackTrace();}}}
}
public class Test{public static void main(String[] args){ArrayBlockingQueue<Computer> queue = new ArrayBlockingQueue<>(20);Producer producer = new Producer(queue);Consumer consumer = new Consumer(queue);producer.start();consumer.start();}
}
1.sleep()方法和wait()方法的区别?
sleep属于Thread类中的静态方法wait()属于Object类中的实例方法
sleep不会释放锁 wait会释放锁
2.notify()方法和notifyAll()方法的区别?
notify()是随机唤醒一个等待的线程 即 执行了wait方法的线程
notifyAll()是唤醒所有等待的线程