1:面试题:
1)jvm是多线程的吗? 是多线程;至少有两条件线程
1)main---"用户线程"
2)垃圾回收线程,回收没有更多的引用对象,从而释放空间;如果没有垃圾回收线程,Java中不断的去new,不断的堆内存空间---->导致OOM(Out Of Memory:内存溢出)
2:创建线程的方式
创建线程的方式1:
1)自定义一个类 继承Thread类
2)重写Thread类的run方法
3)在main()用户线程中,创建当前线程了对象
4)启动线程--->start()不是run方法,run方法是一个普通方法,
线程的创建方式2:
1)自定义一个类,实现Runnable接口
2)重写Runnable接口的run方法
3)在用户线程main中去创建当前类对象--->"资源类"
4)创建Thread类对象,将3)资源类作为Thread类对象的参数进行传递
3:异常处理
throws:抛出
throw:抛出
区别:
1)书写位置的区别
throws:用在方法声明上
throw:用在方法体中
2)后面跟的类型不一样的
throws后面跟的异常类名,可以多个,中间逗号隔开
throw:后面只能一个异常对象,new XXException()
3)是否出现异常的时机
throws:可能出现问题,可能性
throw:执行某个逻辑代码,一定会出现这个异常!(肯定性)
4)处理异常:
throws:抛出给调用者,谁调用这个方法(带有throws的方法),谁必须对这个已处理(throws/try...catch...)
throw:异常的处理:交给方法体中逻辑判断,if(xxx){throw new XXException(...);}
4:校验多线程安全问题的标准 (解决方案)
1)检查程序是否是多线程环境
2)是否存在共享数据
3)是否存在多条语句对共享数据的操作
Java提供了同步代码块,解决上面3),使用同步代码块将多条语句对象共享数据的包起来
Java的同步机制synchronized(锁对象){ //锁对象可以是任意的Java类对象,每一个线程都是用"同一把锁"多条语句对共享数据的操作
5:静态代理:
最大特点:代理角色和真实角色必须实现同一个接口
代理角色:帮助真实角色完成一些事情
真实角色:专注于自己的事情
6:线程的状态
NEW,新建状态
RUNNABLE,运行状态
BLOCKED,线程阻塞状态
WAITTING,死死等待,
TIMED_WAITTING,超时等待
TERMINATED,线程终止/线程死亡
7:线程池
可以通过Executors工厂类(当前类构造方法私有化,对外提供静态方法--->简单工厂模式)提供一些创建线程池的功能
可以创建固定的可重用的线程数的线程池
8:创建线程池的方式
1.newCachedThreadPool
2.newFixedThreadPool
3.newSingleThreadExecutor
4:newScheduleThreadPool
5.newSingleThreadScheduledExecutor
9:ThreadPoolExecutor它的构造方法涉及的相关参数
1.corePoolSize是指线程池中长期存活的线程数.
2.maximumPoolSize线程池允许创建的最大线程数量
3.keepAliveTime空闲线程存活时间
4.TimeUnit:空闲线程存活时间的描述单位
5.BlockingQueue线程池存放任务的队列,用来存储线程池的所有待执行任务
6.ThreadFactory线程池创建线程时调用的工厂方法
7.RejectedExecutionHandler默认的拒绝策略
10:单例设计模式---属于创建型设计模式(创建对象)
概念:始终在内存中有且仅有一个当期类的实例!(有一个对象)
单例设计模式:
1)饿汉式:不会出现安全问题的单例设计模式
1)当前类是具体类
2)类一加载就创建当前类实例
3)构造私有化,对外隐藏,不能new实例
4)对外提供静态方法,返回值当前类本身
public class SinglePattern {
public static void main(String[] args) throws IOException {
//创建学生对象
//Student s = new Student() ;
//Student s2 = new Student() ;
//System.out.println(s==s2) ;//false
//Student.s= null ; //修改了静态实例变量,为了不让你修改,加入private
Student s1 = Student.getStudent();
Student s2 = Student.getStudent() ;
System.out.println(s1 ==s2) ;
System.out.println("---------------------------------");
//创建Runtime实例:获取运行环境
Runtime runtime = Runtime.getRuntime();
//提供一些方法
//availableProcessors()获取cpu处理器的数量
System.out.println(runtime.availableProcessors());
//exec(String dos指令)
System.out.println(runtime.exec("calc"));
System.out.println(runtime.exec("qq"));
}
}
public class Student {
//静态实例:Student一加载,就创建当前类实例
private static Student s = new Student() ;
//对外不能new
private Student(){}
//对外提供静态的方法,返回值是当前类本身
public static Student getStudent(){
return s;
}
}
2)懒汉式:(可能存在安全问题的一种单例模式)
1)当前类是个具体类
2)当前类构造方法私有化
3)当前类的成员位置:声明当前类的一个静态变量
4)对外提供静态方法,返回值是当前类本身:需要判断当前变量是否为null
public class SinglePatter2 {
public static void main(String[] args) {
//获取Theacer对象
Teacher t1 = Teacher.getInstance();
Teacher t2 = Teacher.getInstance();
System.out.println(t1==t2);
}
}
public class Teacher {
//声明静态变量,t的类型Teacher
private static Teacher t ;
//构造方法私有化:
private Teacher(){}
//对外提供静态方法,返回值是当期类本身
//多个线程同时去访问这个方法,
//线程1,线程2,线程3--导致出现线程安全问题
public static synchronized Teacher getInstance(){//变成了静态的同步方法 :锁对象:类名.class
if(t ==null){
t = new Teacher() ;
}
return t;
}
}
11:使用字节输入流将当前项目下的"fis.txt"文件内容读取出来打印在控制台上
public class FileInputStreamDemo {
public static void main(String[] args) {
FileInputStream fis = null ;
try {
//创建文件字节输入流对象FileInputStream(String name)
fis = new FileInputStream("fis.txt") ;
//读取当前项目下的FileOutputStreamDemo3.java文件,把它内容打印控制台上
fis = new FileInputStream("FileOutputStreamDemo3.java") ;
int by = 0 ;
while((by=fis.read())!=-1){
//将字节数by---强转char字符
System.out.print((char)by) ;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
12:使用字节输入流和字节输出流,(分别两种方式进行读写复制操作)
将某个盘符下的c.txt文件中的内容复制到当前项目路径下的Copy.txt文件
public class Test2 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
copy("c.txt", "D:\\课件\\day26\\day26\\code\\copy2");
long end = System.currentTimeMillis();
System.out.println("共耗时:" + (end - start) + "毫秒");
}
private static void copy(String srcFile, String destFile){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
byte[] bytes = new byte[1024];
int len =0;
while ((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
13:方法递归:
方法本身调用方法的一种现象
前提条件:
1)定义一个方法
2)这个方法的逻辑是规律的
3)这个方法是有结束条件,否则---成了"死递归"
需求:
* 求5的阶乘
* 1)可以使用循环解决---求阶乘思想
* 5!= 5*4!
* --->
public class DiGuiDemo {
public static void main(String[] args) {
//求5的阶乘
//定义最终结果变量
int jc = 1 ;
for(int x = 1 ; x <= 5 ; x ++){
jc *= x ;
}
System.out.println("5的阶乘是:"+jc);
System.out.println("----------------------------------------------") ;
System.out.println("5的阶乘是:"+getJc(5));
}
public static int getJc(int n){ //5
if(n==1){
return 1 ;
}else {
//5*getJc(4)
//4*getJc(3)
//3*getJc(2)
//2*getJc(1)
return n * getJc(n-1) ;
}
}
}
14字符输入流---->Reader(抽象类)--->
具体的子类:字符转换输入流InputStreamReader --- 将字节输入流---->转换--->字符输入流
public InputStreamReader(InputStream in):使用平台默认字符集进行解码---读取数据
public InputStreamReader(InputStream in,String charsetName)
使用指定字符集解码---读取数据
public class InputStreamReaderDemo {
public static void main(String[] args) throws Exception {
//创建字符转换输入流对象
//解码:gbk(中国编码表): 一个中文对应两个字节
/* InputStreamReader isr = new InputStreamReader(
new FileInputStream("osw.txt"),"gbk") ;*/
//public InputStreamReader(InputStream in)
InputStreamReader isr = new InputStreamReader(
new FileInputStream("osw.txt")) ;
//读数据
//一次读取一个字符
int by = 0 ;//实际字符数
while((by=isr.read())!=-1){
//展示控制台上 读取的时候将文件内容的里面--->int类型----->转换成字符
System.out.print((char)by);
}
}
}
15:字符流:字符输出流:Writer(抽象类)--->
具体的子类 OutputStreamWriter:字符转换输出流,"可以将字节输出流---转换---字符输出流"
构造方法:
public OutputStreamWriter(OutputStream out):使用平台默认字符集进行编码--输出数据
public OutputStreamWriter(OutputStream out,String charsetName):
使用指定的字符集进行编码---输出数据
public class OutputStreamWriterDemo {
public static void main(String[] args) throws Exception {
//创建一个字符转换输出流对象
//utf-8:一个中文对应三个字节
/* OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("osw.txt"),"utf-8") ;*/
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("osw.txt"));
//写字符串
osw.write("helloworld");
osw.write("高圆圆");
osw.write(97) ;//写入字符,传入参数int--->ASCII码表对应的字符值
//释放资源
osw.close();
}
}
16:键盘录入
0)main方法里面:早期录入 String[] args
1)Scanner(InputStream in)---->Scanner sc = new Scanner(System.in) ;
2)new BufferedReader(new InputStreamReader(System.in))
public class Demo {
public static void main(String[] args) throws IOException {
//字符缓冲输入流需要--->包装字节输入流
// InputStream inputStream = System.in ;
//需要Reader字符流
//Reader reader = new InputStreamReader(inputStream) ;//InputStreamReader(InputStream in)
//创建字符缓冲输入流对象
// BufferedReader br = new BufferedReader(reader) ;
//一步走
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请您输入一个数据:");
String line = br.readLine();
//数字字符串--->
int num = Integer.parseInt(line);
System.out.println("您输入的内容是:"+num);
}
}
17:网络三要素:
ip地址/端口号/协议
18:使用UDP协议发送数据
1)创建发送端的socket对象
2)创建"数据报包"--里面包括:数据内容,ip地址,端口号
3)使用发送端的Socket对象发送"数据报包"
4)释放资源
public class UdpSend {
public static void main(String[] args) throws Exception {
//1)创建发送端的socket对象 ---java.net.DatagramSocket:此类表示用于发送和接收数据报数据包的套接字
//public DatagramSocket()throws SocketException
DatagramSocket ds = new DatagramSocket() ;
//public DatagramPacket(byte[] buf,int length,InetAddress address,int port)
byte[] bytes = "hello,udp我来了".getBytes() ;
int length = bytes.length ;
InetAddress inetAddress = InetAddress.getByName("10.35.165.17") ;
int port = 6666 ;
DatagramPacket dp = new DatagramPacket(bytes,length,inetAddress,port) ;
ds.send(dp) ;
//释放资源
ds.close();
}
}
19:Udp接收端
1)创建接收端的Socket对象
2)创建一个"数据报包"在里面自定义缓冲区:将发送端是数据存储到缓冲区中(字节数组,长度:1024或者1024的整数倍)
3)使用2)接收容器(缓冲区),接收发送端的数据
4)解析接收容器中的实际内容
5)展示数据即可
6)释放接收端的资源
public class UdpReceive {
public static void main(String[] args) throws Exception {
//1)创建接收端的Socket对象
//public DatagramSocket(int port)throws SocketException
DatagramSocket ds = new DatagramSocket(6666) ;
//public DatagramPacket(byte[] buf,int length)
byte[] buffer = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(buffer,buffer.length) ;
ds.receive(dp) ;
//4)解析接收容器中的实际内容
//public byte[] getData() :解析数据报包中DatagramPacket
// 缓冲的实际的字节数组
byte[] bytes = dp.getData();
//public int getLength():解析数据报包中DatagramPacket中的实际字节数组长度
int length = dp.getLength();
//展示数据
String message = new String(bytes,0,length) ;
//谁发送的数据---获取ip地址字符串形式
//数据报包DatagramPacket--->public InetAddress getAddress()
//InetAddress:ip地址--->String getHostAddress()
String ip = dp.getAddress().getHostAddress() ;
System.out.println("data from is--->"+ip+",data is--->"+message) ;
//释放资源
ds.close();
}
}
20:发送端不断键盘录入数据,接收端不断展示数据,在一个窗口中聊天!使用多线程的方式:开启两条线程,一条线程:发送端发送数据另一条线程:接收端不断接收数据,展示数据
public class ChatRoom {
public static void main(String[] args) {
try {
//创建发送端Socket
DatagramSocket sendDs = new DatagramSocket() ;
//创建接收端的Socket
DatagramSocket receiveDs = new DatagramSocket(10086) ;
//创建发送端的线程所在的资源类对象
SendTread st = new SendTread(sendDs) ;
//创建接收端的线程所在资源类对象
ReceiveThread rt = new ReceiveThread(receiveDs) ;
//创建线程
Thread t1 = new Thread(st) ;
Thread t2 = new Thread(rt) ;
//启动线程
t1.start();
t2.start();
} catch (SocketException e) {
e.printStackTrace();
}
}
}
接收端的资源类
*/
public class ReceiveThread implements Runnable{
private DatagramSocket ds ;
public ReceiveThread(DatagramSocket ds){
this.ds = ds ;
}
@Override
public void run() {
try {
//不断的展示数据
while(true){
//接收数据:接收容器
byte[] buffer = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(buffer,buffer.length) ;
//接收
ds.receive(dp) ;
//解析缓冲区(接收容器)的数据
String message = new String(dp.getData(),0,dp.getLength()) ;
//获取ip地址
String ip = dp.getAddress().getHostAddress() ;
System.out.println("data from --->"+ip+",content is--->"+message);
}
} catch (IOException e) {
e.printStackTrace();
}
//接收端不需要释放资源,一直开启状态
}
}
发送端的资源类
*/
public class SendTread implements Runnable{
private DatagramSocket ds ;
public SendTread(DatagramSocket ds){
this.ds = ds ;
}
@Override
public void run() {
try {
//键盘录入数据--->BufferedReader
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)) ;
String line = null ;
while((line=br.readLine())!=null){
//数据报包:将数据发送接收端
DatagramPacket dp = new DatagramPacket(
line.getBytes(),
line.getBytes().length,
InetAddress.getByName("10.35.165.17"),
10086) ;
//发送数据
ds.send(dp) ;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
ds.close();
}
}
}