线程池存在的意义:
1.系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期 很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理的时间.
2.系统资源的消耗,这样就有点"舍本逐末"了。针对这一种情况,为了提高性能,我们就可以采用线程 池。线程池在启动的时,会创建大量空闲线程(没有执行任务的线程),当我们向线程池提交任务的时,线程池 就会找到一个空闲线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次放回到线程池中称 为空闲状态。等待下一次任务的执行。这样就可以达到对线程对象重复利用的效果.
JDK对线程池也进行了相关的实现,在真实企业开发中我们也很少去自定义线程池,而是使用JDK中自带的线程池
理解:
提前准备好一定数量的线程对象的一个容器,得到线程池就相当于得到了线程对象
我们可以使用Executors中所提供的静态方法来创建线程池
①static ExecutorsService newCachedThreadPool() 创建一个默认的线程池
②static ExecutorService newFixedThreadPool(int nThreads)创建一个指定最多线程数量的线程池
③static ExecutorsService newSingleThreadExecutor() 创建只有一个线程对象的线程池
使用:
①准备线程任务【Runnable Callable】
②把线程任务提交给线程池【自动委派内部线程对象来执行】
功能:
submit(Runnable r):提交线程任务到线程池执行
submit(Callable c):提交线程任务到线程池执行
shutdown():关闭线程池
shutdownNow():关闭线程池
代码示例:
static ExecutorsService newCachedThreadPool() 的使用
package com.offcn.demo01;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo02 {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 1; i <= 100; i++) {
final int J = i;
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"---任务"+J);
}
};
pool.submit(r);
}
pool.shutdown();
}
}
static ExecutorService newFixedThreadPool(int nThreads)
package com.offcn.demo01;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo03 {
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(5);
for (int i = 1; i <=100 ; i++) {
final int J = i;
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"任务"+J);
}
});
}
pool.shutdown();
}
}
static ExecutorsService newSingleThreadExecutor()
package com.offcn.demo01;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo04 {
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 1; i <=100 ; i++) {
final int J = i;
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"任务"+J);
}
});
}
pool.shutdown();
}
}
枚举是和类以及接口同一个级别的类型(都是引用类型的数据),可以理解为它是一种特殊类的体现,本质就是类(枚举类型编译后也会生成字节码文件).
特殊:枚举是对只有有限对象个数的类的描述(枚举类型中提供对象个数是在定义枚举的时候就已经决定,外面不能添加枚举对象,在外面只能获取枚举对象使用), 比如:星期只能有7个对象 月份类对应的对象个数12个,季节类4个季节对象 .....
枚举的应用场景:如果某个类型,只有有限个对象个数,不要使用class定义这个类型,而是使用枚举定义该类型.
枚举有自己的关键字: enum
修饰符 enum 枚举名{
枚举项1,枚举项2,枚举项3[;]如果枚举中只有枚举项,最后分号可以省略
}
注意:定义枚举类要用关键字enum
枚举项:枚举的对象
示例代码:
package com.offcn.demo04;
public enum Gender {
MAN,WOMAN;
}
package com.offcn.demo04;
public class UseGender {
public static void main(String[] args) {
//枚举类型的使用
//枚举类型名.枚举项名
System.out.println(Gender.MAN);
System.out.println(Gender.WOMAN);
}
}
①除了枚举项以外,还可以定义:构造方法、成员变量、成员方法、抽象方法
注意:枚举项必须卸载第一行;
枚举项的形态:
只有枚举项名:SPRING -----普通类的空参构造
有参数的枚举项:SPRING(“春天”) ------普通类的有参构造对象
有参数有方法重写(见代码示例)
代码示例:
package com.offcn.demo04;
public enum Season {
SPRING("春天"){
@Override
public void say() {
System.out.println("春雨贵如油,润物细无声");
}
},SUMMER("夏天"){
@Override
public void say() {
System.out.println("映日荷花别样红");
}
},FALL("秋天"){
@Override
public void say() {
System.out.println("自古逢秋悲寂寥,我言秋日胜春朝");
}
},WINTER{
@Override
public void say() {
System.out.println("忽如一夜春风来,千树万树梨花开");
}
};
public void show(){
System.out.println("showSeason");
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
Season() {
System.out.println("空参构造");
}
Season(String name){
this.name=name;
System.out.println("有参构造");
}
public abstract void say();
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
'}';
}
}
package com.offcn.demo04;
public class UseSeason {
public static void main(String[] args) {
System.out.println(Season.SPRING);
//Season.SPRING.say();
Season s = Season.SPRING;
System.out.println(s.getName());
s.say();
s.show();
}
}
①所有枚举类都是Enum的子类
②我们可以通过 枚举类名.枚举项名 去访问指定的枚举项
③每一个枚举项其实就是该枚举的一个对象
④枚举也是一个类,也可以定义成员变量、成员方法、抽象方法
⑤枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,分号必须写
⑥枚举类可以有构造器,但必须是private的,他默认的也是private的
枚举项的用法比较特殊:枚举项(实参);
⑦枚举类也可以有抽象方法,但是枚举项必须重写该方法
代码示例:
package com.offcn.demo04;
public class UseSeason {
public static void main(String[] args) {
System.out.println(Season.SPRING);
//Season.SPRING.say();
Season s = Season.SPRING;
System.out.println(s.getName());
s.say();
s.show();
System.out.println(Season.SPRING.name());
System.out.println(Season.WINTER.ordinal());
System.out.println(Season.WINTER.compareTo(Season.SUMMER));
System.out.println(s.toString());
Season[] sea = Season.values();
for (Season seas : sea) {
System.out.println(seas.name());
}
}
}
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路(网线,光纤,WiFi) 连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机 系体系
Java网络编程是在已经搭建好的计算机网络环境下实现的.
Java网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把
数据进行解析,从而提取出对应的信息,达到通信的目的.
要想让计算机网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接收 数据的计算机和识别发送的计算机,而IP地址就是这个标识号.也就是设备的标识.【唯一性】
网络的通信,本质上是两个应用程序的通信.每台计算机都有很多的应用程序,那么在网络通信时,如何区分这些 应用程序呢?如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的应用程序了.也就 是应用程序的标识.
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的 规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样.在计算机网络中,这些连接和通信的规则被称为 网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数 据交换. 常见的协议有UDP协议和TCP协议,最常见的是http|https.
是给每个连接在网络上的主机分配一个32bit地址.按照TCP/IP协议,IP地址用二进制来表示,每个IP地址长 32bit,也就是4个字节.例如一个采用二进制形式的IP地址是“11000000 10101000 00000001 01000010”,这么长的地址,处理起来也太费劲了.为了方便使用,IP地址经常被写成十进制的形式,中间使用 符号“.”分隔不同的字节.于是,上面的IP地址可以表示为“192.168.1.66”.IP地址的这种表示法叫做“点分 十进制表示法”,这显然比1和0容易记忆得多.最多能表示:2^32大概是43亿IP地址, 一个人手中大概有2~3电 脑设备, 20亿有设备. 60亿个IP.
由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张.为了扩大 地址空间,通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,这样就解 决了网络地址资源数量不够的问题, IPv6可以实现为地球上每一粒沙子分配一个IP地址. 2^128次方
InetAddress此类表示Internet协议地址,默认获取都是IPv4下的IP地址
相关方法
代码示例:
package com.offcn.demo05;
import java.net.InetAddress;
public class Demo01 {
public static void main(String[] args) throws Exception{
InetAddress ip1 = InetAddress.getByName("LAPTOP-M0ML11FR");
System.out.println(ip1);
System.out.println(ip1.getHostName());
System.out.println(ip1.getHostAddress());
System.out.println(ip1.getLocalHost());
}
}
端口号的作用:设备上应用程序的唯一标识
用两个字节表示的非负整数,它的取值范围是0~65535.其中,0~1023之间的端口号用于一些知名的网络服务 和应用,普通的应用程序需要使用1024以上的端口号.如果端口号被另外一个服务或应用所占用,会导致当前程 序启动失败.
需要记忆的端口号:
mysql:3306
tomcat:8080
QQ:4301
大部分程序系统会随机分配端口号,当然也可以手动指定.
指令: netstat -ano 查看电脑所有运行的程序信息,会看到端口号.