线程池:
线程池就是可以用来复用线程的技术(假如无法复用一个线程,如果任务一下子过多,就会创建出过多的线程,占用过多的cpu等)
得到线程池对象:
方法1:
使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。
运用ThreadpoolExecutor创建线程池(即new ThreadPoolExecutor())
然后使用一个ExecutorServes类型的变量去记录这个new出来的ThreadPoolExecutor类
方法2:
使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象。
线程池中的参数:
int corePoolSize | 指定线程池的核心线程的数量。 计算密集型任务:核心线程数=CPU核+1 IO密集型任务: 核心线程数=CPU核数*2 |
---|---|
int maximumPoolSize | 指定线程池的最大线程数量。 |
long keepAliveTime | 指定临时线程的存活时间。 |
TimeUnit unit | 指定临时线程存活的时间单位(秒、分、时、天) TimeUnit.SECONDS 使用TimeUnit导出时间 |
BlockingQueue<Runnable> workQueue | 指定线程池的任务队列 new ArrayBlockingQueue<>(4) 上方代码指任务队列可以容纳四个线程 |
ThreadFactory threadFactory | 指定线程池的线程工厂。 Executors.defaultThreadFactory() 使用Executors调用defaultThreadFactory() |
RejectedExecutionHandler handler) | 指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理) |
什么时候创建临时线程?
新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。
什么时候开始任务拒绝策略?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务。
ExecutorService的常用方法:
void execute(Runnable command) | 执行 Runnable 任务 |
Future<T> submit(Callable<T> task) | 执行 Callable 任务,返回未来任务对象,用于获取线程返回的结果 |
void shutdown() | 等全部任务执行完毕后,再关闭线程池! |
List<Runnable> shutdownNow() | 立刻关闭线程池,停止正在执行的任务,并返回队列中未执行的 |
新任务拒绝策略:
Executors
在方法2创建线程中:Executors是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象。
注意 :这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象。
缺点:
大型并发系统环境中使用Executors如果不注意可能会出现系统风险。
网络通信:
网络通信三要素:IP地址,端口号,协议
ip是在网络中找到目标设备的唯一凭据
端口号是目标设备中每个软件都具备的,相当于这个设备中的身份证号码
协议:在网络通信中传输数据的规范,相当于交通法规
ip
ip是设备在网络中的地址,是设备在网络中的唯一标志 设备之间可以通过ip地址来寻找对方从而建立起网络通信关系 ip地址由连接宽带时运营商负责赋予 ip地址有两种形式,一种是IPv4,一种是IPv6 特殊ip地址:127.0.0.1 、localhost代表本机ip ip常用命令:ipconfig查看本机ip地址 、ping ip地址:检查网络是否连通 IPv4是一种由32个字符即四个字节构成的一种ip地址,一般以二进制形式, 可以缩写到每八个字符即一个字节转化为十进制然后每个字节之间以下标点为间隔 例如:11000000 10101000 00000001 01000010可以表示为192.168.1.66 IPv6是一种由128个字符即16个字节构成的一种ip地址,一般以二进制形式, 可以缩写到总共分成8段,每段分成4小节(每个小节由四个字符构成)每个小节缩写为一位十六进制数字,每个段之间用冒号分割 例如:0010 0000 0000 0001 0000 1101 1011 1000这两段可以表示为2001:0db8
网址的由来
InetAddress是一个代表ip的类
端口
端口用来标记一个正在计算机上运行的应用程序,被规定为一个16位的2进制,范围是0~65535 周知端口:0~1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21) 自己开发的应用程序一般选用注册端口1024~49151 注册端口:1024~49151,分配给用户进程或某些应用程序。 动态端口:49152到65535,之所以称为动态端口,是因为它 一般不固定分配某种进程,而是动态分配。 一个设备中不能出现两个应用程序端口号一样,否则出错
网络通信协议:
协议:传输层的两个通信协议:UDP用户数据报协议 TCP传输控制协议
UDP特点:无连接,不可靠通信。 体现在于: 数据按照包发,一个数据包包含ip 程序端口 目的地ip 程序端口和数据(限制在64KB内) 发送发不管对方是否在线,数据丢失也不管,接收方收到数据也不返回,让发送方不确定接收方是否收到,故而是不可靠的 但通信效率高 用处:语音通话、视频直播
TCP通信: 面向连接可靠通信 目的:保证在不可靠的信道上实现可靠的通信 方法: 1.三次握手建立可靠连接 2.传输数据会进行确认以保证传输数据的可靠性 3.四次挥手断开连接 通信效率相对较差 用处:网页浏览,文件下载,支付
UDP通信:
java提供了java.net.DatagramSocket来实现UDP通信
DatagramSocket userport = new DatagramSocket();//使用无参构造器创建客户端端口系统会随即为客户端分配一个端口
// 可以在括号中填上想要的端口,但有可能会与原有端口冲突,所以使用空白,不填端口让程序自动分配端口,就不会使其与原本已经存在都端口冲突的
/*
public DatagramPacket(byte buf[], int offset, int length,
InetAddress address, int port) {
*/
byte b[]="这里是客户端数据".getBytes();
DatagramPacket packet = new DatagramPacket(b, b.length, InetAddress.getLocalHost(), 5555);
userport.send(packet);
System.out.println("客户端已发送");
userport.close();
byte b1[]=new byte[1024*64];
DatagramPacket packet1 = new DatagramPacket(b1, b1.length);
DatagramSocket Socket = new DatagramSocket(6666);//注册端口
Socket.receive(packet1);
System.out.println("服务端已接收");
//获取数据包本次接受了多少数据
int len = packet1.getLength();
//String s = Arrays.toString(b1);
//System.out.println(s);
String s1 = new String(b1,0,len);//读多少倒多少
System.out.println(s1);
Socket.close();
//服务端不仅可以接收到客户端发送的数据还可以接收到客户端的IP、端口
System.out.println(packet1.getAddress());
System.out.println(packet1.getPort());
想要实现多发多收可以用死循环包住接收数据方法和发生数据的方法
TCP通信:
Java提供了java.net.Socket 来实现TCP通信
因为有发出的基本上就是字符串,所以使用readUTF和 writeUTF这两个方法发出与接收
try (
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream os= socket.getOutputStream();
DataOutputStream dos=new DataOutputStream(os);//数据输入流和数据输出流比较适合做通信
){
dos.writeUTF("这里是字符串数据TCP");//这边用writeUTF发数据那边就应该用readUTF去读取
//关闭外部包装流会自动关闭内部原始流
} catch (IOException e) {
throw new RuntimeException(e);
}
try (
ServerSocket sso=new ServerSocket(9999);
){
//System.out.println(sso.accept());//得到一个Socket对象Socket[addr=/127.0.0.1,port=53096,localport=9999]
Socket sk = sso.accept();
InputStream is = sk.getInputStream();
DataInputStream dis=new DataInputStream(is);
System.out.println(dis.readUTF());
} catch (IOException e) {
throw new RuntimeException(e);
}
多发多收:
也是要使用死循环包住发出与接收方法
BS架构:
服务器必须给浏览器响应HTTP协议规定的数据格式,否则浏览器不识别返回的数据。
注意可以使用线程池进行优化
单元测试junit
单元测试就是针对最小的功能单元(方法),编写测试代码对该功能进行正确性测试。
JUnit是使用Java语言实现的单元测试框架,它是第三方公司开源出来的,很多开发工具已经集成了Junit框架,比如IDEA。所以可以直接使用,不用去下载
优点:
编写的测试代码很灵活,可以指某个测试方法执行测试,也支持一键完成自动化测试。 不需要程序员去分析测试的结果,会自动生成测试报告出来。 提供了更强大的测试能力。
单元测试框架常用注解:
建议使用junit 4
反射
反射指的是允许以编程方式访问已加载类的成分(成员变量、方法、构造器等)。
反射第一步:获取类:Class
反射的第一步都是先得到加载后的类,然后才可以去那类的其他成分。
方式一:Class c1 = Class.forName(“全类名”);
方式二:Class c2 = 类名.class
方式三:Class c3 = 对象.getClass();
获取类的构造器:Constructor
使用获取的构造器对象调用下列的方法
作用:
如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象 setAccessible(boolean) 反射可以破坏封装性,私有的也可以执行了。
获取类的成员变量:Field
获取成员变量的作用依然是在某个对象中取值、赋值
获取类的成员方法:Method