tcp多线程
tcp客户端 多线程收发代码
package com.heima.test2;
import java.io.*;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.Scanner;
class ClientSend implements Runnable {
Socket socket;
Scanner sc = new Scanner(System.in);
public ClientSend(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
System.out.println("输入发送的内容");
String text = sc.next();
//发送 创建字符缓冲流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "gbk"));
//写数据
bw.write(text);
//bw.newLine();如果接收方 按行接收 这里就需要添加newLine
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ClientReceive implements Runnable {
Socket socket;
public ClientReceive(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
//接收
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "gbk"));
//创建字符数组用来接收数据
char[] cs = new char[1024];
int len;
//读取网络中的数据 存到字符数组中
while ((len = br.read(cs)) != -1) {
System.out.println(new String(cs, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class Demo01 {
public static void main(String[] args) {
try {
//创建发送端的socket对象 连接服务端的ip和端口
Socket socket = new Socket("127.0.0.1", 15000);
System.out.println("连接到服务器成功");
//发送任务
ClientSend clientSend = new ClientSend(socket);
//接收的任务
ClientReceive clientReceive = new ClientReceive(socket);
//开启两个任务
new Thread(clientSend).start();
new Thread(clientReceive).start();
//socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
tcp服务端 多线程收发代码
package com.heima.test2;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
class ServerSend implements Runnable {
Socket accept;
Scanner sc = new Scanner(System.in);
public ServerSend(Socket accept) {
this.accept = accept;
}
@Override
public void run() {
//发送 创建字符缓冲流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream(), "gbk"));
while (true) {
try {
System.out.println("输入发送的内容");
String text = sc.next();
//写数据
bw.write(text);
//bw.newLine();如果接收方 按行接收 这里就需要添加newLine
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class ServerReceive implements Runnable {
Socket accept;
public ServerReceive(Socket socket) {
this.accept = accept;
}
@Override
public void run() {
BufferedReader br = new BufferedReader(new InputStreamReader(accept.getInputStream(), "gbk"));
while (true) {
try {
//接收
//创建字符数组用来接收数据
char[] cs = new char[1024];
int len;
//读取网络中的数据 存到字符数组中
while ((len = br.read(cs)) != -1) {
System.out.println(new String(cs, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class Demo02 {
public static void main(String[] args) {
try {
//创建服务端socket对象
ServerSocket ss = new ServerSocket(15000);
//接收客户端的请求
Socket accept = ss.accept();
System.out.println("收到来自" + accept.getRemoteSocketAddress() + "的连接");
//发送任务
ClientSend clientSend = new ClientSend(accept);
//接收的任务
ClientReceive clientReceive = new ClientReceive(accept);
//开启两个任务
new Thread(clientSend).start();
new Thread(clientReceive).start();
//socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
原子类AtomicInteger
-
原子性
- 所谓的原子性是指在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可以分割的整体。
-
public AtomicInteger(): 初始化一个默认值为0的原子型Integer
-
public AtomicInteger(int initialValue): 初始化一个指定值的原子型Integer
-
int get(): 获取值
-
int getAndIncrement(): 以原子方式将当前值加1,注意,这里返回的是自增前的值。 相当于i++
-
int incrementAndGet(): 以原子方式将当前值加1,注意,这里返回的是自增后的值。 相当于++i
-
int addAndGet(int data): 以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回结果。 +=
-
int getAndSet(int value): 以原子方式设置为newValue的值,并返回旧值。
乐观锁和悲观锁
乐观锁
日志
1概述
-
概述
程序中的日志可以用来记录程序在运行的时候点点滴滴。并可以进行永久存储。
-
日志与输出语句的区别
输出语句 日志技术 取消日志 需要修改代码,灵活性比较差 不需要修改代码,灵活性比较好 输出位置 只能是控制台 可以将日志信息写入到文件或者数据库中 多线程 和业务代码处于一个线程中 多线程方式记录日志,不影响业务代码的性能
2日志体系结构和logback
- 体系结构
-
logback
通过使用logback,我们可以控制日志信息输送的目的地是控制台、文件等位置。
我们也可以控制每一条日志的输出格式。
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
3入门案例【应用】
- 使用步骤
- 导入logback的相关jar包
相关资料网盘地址:https://www.aliyundrive.com/s/wMiqbd4Zws6
- 编写logback配置文件
-
在代码中获取日志的对象
- 注意导包 org.slf4j.xxx
-
按照级别设置记录日志信息
- 代码示例
public class Demo01 {
private static final Logger LOGGER = LoggerFactory.getLogger(Demo01.class);
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入您的姓名");
String name = sc.next();
LOGGER.debug("姓名是" + name);
LOGGER.info("输了用户的姓名" + name);
System.out.println("请输入您的年龄");
String age = sc.next();
LOGGER.info("输了用户的年龄" + age);
try {
LOGGER.warn("警告年龄必须是个数字,必须在正常范围内");
int ageInt = Integer.parseInt(age);
LOGGER.debug("姓名格式正确" + age);
} catch (NumberFormatException e) {
LOGGER.error("警告你不听 错了吧 " + age);
}
}
}
日志级别
- 默认debug级别
// 测试类
public class Test01 {
//获取日志的对象
private static final Logger LOGGER = LoggerFactory.getLogger(Test01.class);
public static void main(String[] args) {
//1.导入jar包
//2.编写配置文件
//3.在代码中获取日志的对象
//4.按照日志级别设置日志信息
LOGGER.debug("debug级别的日志");
LOGGER.info("info级别的日志");
LOGGER.warn("warn级别的日志");
LOGGER.error("error级别的日志");
}
}
枚举(掌握)
1概述
为了间接的表示一些固定的值,Java就给我们提供了枚举
是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内
2定义格式
- 格式
public enum s {
枚举项1,枚举项2,枚举项3;
}
注意: 定义枚举类要用关键字enum
- 示例代码
// 定义一个枚举类,用来表示春,夏,秋,冬这四个固定值
public enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
3枚举的特点【理解】
-
特点
-
所有枚举类都是Enum的子类
-
我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项
-
每一个枚举项其实就是该枚举的一个对象
-
枚举也是一个类,也可以去定义成员变量
-
枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
-
枚举类可以有构造器,但必须是private的,它默认的也是private的。
枚举项的用法比较特殊:枚举(“”);
-
枚举类也可以有抽象方法,但是枚举项必须重写该方法
-
-
示例代码
public enum Season {
SPRING("春"){
//如果枚举类中有抽象方法
//那么在枚举项中必须要全部重写
@Override
public void show() {
System.out.println(this.name);
}
},
SUMMER("夏"){
@Override
public void show() {
System.out.println(this.name);
}
},
AUTUMN("秋"){
@Override
public void show() {
System.out.println(this.name);
}
},
WINTER("冬"){
@Override
public void show() {
System.out.println(this.name);
}
};
public String name;
//空参构造
//private Season(){}
//有参构造
private Season(String name){
this.name = name;
}
//抽象方法
public abstract void show();
}
public class EnumDemo {
public static void main(String[] args) {
/*
1.所有枚举类都是Enum的子类
2.我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项
3.每一个枚举项其实就是该枚举的一个对象
4.枚举也是一个类,也可以去定义成员变量
5.枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,
但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
6.枚举类可以有构造器,但必须是private的,它默认的也是private的。
枚举项的用法比较特殊:枚举("");
7.枚举类也可以有抽象方法,但是枚举项必须重写该方法
*/
//第二个特点的演示
//我们可以通过"枚举类名.枚举项名称"去访问指定的枚举项
System.out.println(Season.SPRING);
System.out.println(Season.SUMMER);
System.out.println(Season.AUTUMN);
System.out.println(Season.WINTER);
//第三个特点的演示
//每一个枚举项其实就是该枚举的一个对象
Season spring = Season.SPRING;
//调用成员变量
System.out.println(Season.SPRING.name);
System.out.println(Season.SUMMER.name);
//调用重写的show方法
Season.AUTUMN.show();
Season.WINTER.show();
}
}
4枚举的方法【应用】
-
方法介绍
方法名 说明 String name() 获取枚举项的名称 int ordinal() 返回枚举项在枚举类中的索引值 int compareTo(E o) 比较两个枚举项,返回的是索引值的差值 String toString() 返回枚举常量的名称 static T valueOf(Class type,String name) 获取指定枚举类中的指定名称的枚举值 values() 获得所有的枚举项 -
示例代码
public enum Season {
SPRING,SUMMER,AUTUMN,WINTER;
}
public class EnumDemo {
public static void main(String[] args) {
// String name() 获取枚举项的名称
String name = Season.SPRING.name();
System.out.println(name);
System.out.println("-----------------------------");
// int ordinal() 返回枚举项在枚举类中的索引值
int index1 = Season.SPRING.ordinal();
int index2 = Season.SUMMER.ordinal();
int index3 = Season.AUTUMN.ordinal();
int index4 = Season.WINTER.ordinal();
System.out.println(index1);
System.out.println(index2);
System.out.println(index3);
System.out.println(index4);
System.out.println("-----------------------------");
// int compareTo(E o) 比较两个枚举项,返回的是索引值的差值
int result = Season.SPRING.compareTo(Season.WINTER);
System.out.println(result);//-3
System.out.println("-----------------------------");
// String toString() 返回枚举常量的名称
String s = Season.SPRING.toString();
System.out.println(s);
System.out.println("-----------------------------");
// static <T> T valueOf(Class<T> type,String name)
// 获取指定枚举类中的指定名称的枚举值
Season spring = Enum.valueOf(Season.class, "SPRING");
System.out.println(spring);
System.out.println(Season.SPRING == spring);
System.out.println("-----------------------------");
// values() 获得所有的枚举项
Season[] values = Season.values();
for (Season value : values) {
System.out.println(value);
}
}
}