Day 16
一、线程优先级
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定应
调度哪个线程来执行。
线程的优先级用数字表示,范围从1到10。
一个线程的默认优先级是5。
setPriority(int newPriority) 改变这个线程的优先级
注意:优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高后调用优先级低的线程。
public class ThreadDemo01 implements Runnable{
public static void main(String[] args) {
ThreadDemo01 demo = new ThreadDemo01();
Thread th1 = new Thread(demo,"A");
Thread th2 = new Thread(demo,"B");
Thread th3 = new Thread(demo,"C");
//设置优先级
th1.setPriority(Thread.MIN_PRIORITY);
th3.setPriority(10);
th1.start();
th2.start();
th3.start();
//查看优先级
System.out.println(th1.getPriority());
System.out.println(th2.getPriority());
System.out.println(th3.getPriority());
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
二、线程通信
同步问题的典型示例是“生产者-消费者”模型,也就是生产者线程只负责生产,消费者线程只负责消费,在消费者发现无内容可消费时则睡觉
-
线程通信 生产者消费者模式
wait() 等待 当一个线程wait,会进入到对象的等待池中,等待被唤醒
让出cpu的资源,让出 对象锁资源
notify() 唤醒随机一个 唤醒对象等待池中的线程,被唤醒的线程会进入到就绪状态,满足使用条件才可以使用
notifyAll() 唤醒全部
必须要使用在一个同步的环境下
public class Demo03 {
public static void main(String[] args) {
Street street = new Street();
//人线程 车线程
new Thread(new Person(street)).start();
new Thread(new Car(street)).start();
}
}
//街道资源
class Street{
//红绿灯
private boolean flag = false;
//东西->人 -->false
public void we() {
//true-->wait()
if(flag != false) {
try {
this.wait(); //当前线程进入到this对象的等待池中
} catch (InterruptedException e) {
e.printStackTrace();
}
}else { //人走
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("人走......");
//改变信号灯 唤醒对方
flag = true;
this.notify();
}
}
//南北 --> 车 -->true
public void ns() {
//false-->wait()
if(flag != true) {
try {
this.wait(); //当前线程进入到this对象的等待池中
} catch (InterruptedException e) {
e.printStackTrace();
}
}else { //车走
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("车走......");
//改变信号灯 唤醒对方
flag = false;
this.notify();
}
}
}
class Person implements Runnable{
//资源
private Street street;
public Person(Street street) {
this.street = street;
}
@Override
public void run() {
while(true) {
street.we();
}
}
}
class Car implements Runnable{
//资源
private Street street;
public Car(Street street) {
this.street = street;
}
@Override
public void run() {
while(true) {
street.ns();
}
}
}
如何解决死锁问题:
- 往往是程序逻辑的问题。需要修改程序逻辑。
- 尽量不要同时持有两个对象锁
三、网络编程
网络编程:底层 数据如何传输,使用哪种协议
网页编程: 上层
网络编程:
1)如何定位到一台电脑 – IP(人的身份证号码) 定位网络上的节点(电子设备)
2)如何区分多个软件 – (端口)
3)如何区分一个软件中的多个资源 – url
共组织内部使用的额非注册IP: 192.168.0.0 ~ 192.168.255.255
127.0.0.1 本机IP
localhost ->本机
public class NetDemo01 {
public static void main(String[] args) throws UnknownHostException {
//static InetAddress getLocalHost() 返回本地主机的地址。
InetAddress i1 = InetAddress.getLocalHost();
System.out.println(i1); //DESKTOP-P04TCL5/192.168.14.111
//static InetAddress getByName(String host) 决定了IP地址的主机,主机的名字。
InetAddress i2 = InetAddress.getByName("www.baidu.com");
System.out.println(i2); //www.baidu.com/180.101.49.12
System.out.println(i1.getHostName()); //DESKTOP-P04TCL5
System.out.println(i1.getHostAddress()); //192.168.14.111
}
}
四、端口
端口: port – 区分软件
2个字节 0~65535
同一个写一下端口号不能冲突
8000以下的端口号不建议使用–>预留端口号
-
常见的端口号:
80 http
8080 tomcat
3306 mysql
1521 oracle
public class PortDemo02 {
public static void main(String[] args) {
//InetSocketAddress(int port) 创建一个套接字地址的IP地址在哪里通配符地址和端口号一个指定的值。
InetSocketAddress in= new InetSocketAddress("localhost",8888);
System.out.println(in);
//ip
System.out.println(in.getHostName());
//端口号
System.out.println(in.getPort());
}
}
五、URL
URL : 统一资源定位符
互联网三大基石 : html http url
URL->类
public class URLDemo03 {
public static void main(String[] args) throws MalformedURLException {
//URL(String spec)
URL url = new URL("http://www.baidu.com:80/index.html?name=zhangsan&pwd=123#a");
System.out.println(url);
//getProtocol() 协议
System.out.println("协议:"+url.getProtocol());
System.out.println("域名:"+url.getHost());
System.out.println("端口:"+url.getPort());
System.out.println("资源:"+url.getFile()); ///index.html?name=zhangsan&pwd=123
System.out.println("文件:"+url.getPath());
System.out.println("数据:"+url.getQuery());
System.out.println("锚点:"+url.getRef());
}
}
六、传输层协议
* Socket 套接字
* 相当于传输层为应用层开辟的一个小口子
* 不同协议下Socket实现不同
* 面向Socket编程
1.UDP
UDP:UDP(UserDatagramProtocol ) 发送短信 非面向连接、不安全、数据可能丢失 、效率高,只管写只管发送
UDP实现基本流程: 发送端
-
1.定义发送端 DatagramSocket(int port) 指定发送端ip和端口
-
2.准备数据–> 转为字节数组
-
3.打包 DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造一个数据报包发送数据包的长度 length抵消 ioffsetto指定主机上的指定端口号。
-
4.发送数据 send(DatagramPacket p) 从这个套接字发送一个数据报包。
-
5.关闭
–文件的传输—> 从本地文件中 读取数据–>传输到对方–>接收到数据–>写出指定本地位置
public class UDPSend01 { public static void main(String[] args) throws IOException { System.out.println("--------------我是发送端-----------------------------------"); //1.定义发送端 DatagramSocket(int port) 指定发送端ip和端口 DatagramSocket send = new DatagramSocket(7777); //2.数据 byte[] msg = "千年等一回".getBytes(); //3.打包 DatagramPacket packet = new DatagramPacket(msg,0,msg.length,new InetSocketAddress("localhost", 8888)); //4.发送 send.send(packet); //5.关闭 send.close(); } }
UDP实现基本流程: 接收端
- 1.构建接收端
- 2.准备包裹–>用来接收数据
- 3.接收
- 4.处理数据
- 5.关闭
public class UDPReceive02 {
public static void main(String[] args) throws IOException {
System.out.println("--------------我是接收端-----------------------------------");
//1.构建接收端
DatagramSocket receive = new DatagramSocket(8888);
//2.准备包裹-->用来接收数据
byte[] arr = new byte[1024*60];
DatagramPacket packet = new DatagramPacket(arr,arr.length);
//3.接收
receive.receive(packet);
//4.处理数据
/*
* byte[] getData()
返回数据缓冲区。
int getLength()
返回将要发送或接收到的数据的长度。
*/
byte[] result = packet.getData();
int length = packet.getLength();
System.out.println(new String(result,0,length));
//5.关闭
receive.close();
}
}
2.TCP
TCP:TCP(transfer control protocol) 打电话 面向连接、安全、可靠,效率低,送端和接受端两端平等
基于 tcp 协议,建立稳定连接的点对点的通信;实时、快速、安全性高、占用系统资源多、效率低;“请求-响应”模式:
a)、客户端:在网络通讯中,第一次主动发起通讯的程序被称作客户端(Client)程序
b)、服务器:第一次通讯中等待连接的程序被称作服务器端(Server)程序
• Socket:发送 TCP 消息
• ServerSocket:创建服务器
服务器:
①创建服务器 指定端口
②等待客户端连接
③分析接收数据
客户端:
①连接服务器: 创建客户端 +指定服务器地址 +端口
②发送数据
TCP 基本流程: 服务端
- 1.创建服务端 ServerSocket(int port) 创建绑定到特定端口的服务器套接字。 服务端的端口号
- 2.阻塞式监听
- 3.获取IO流
- 4.读入数据
- 5.操作数据
- 6.关闭
public class TCPClient03 {
public static void main(String[] args) throws UnknownHostException, IOException {
String name = "laopei";
String pwd = "0523";
System.out.println("---------------client--------------");
//1.创建客户端
Socket client = new Socket("127.0.0.1",8888);
//2.获取输入流
OutputStream os = client.getOutputStream();
//3.写出数据
os.write(("name="+name+"&pwd="+pwd).getBytes());
os.flush();
//获取输入流读取服务端响应
InputStream is = client.getInputStream();
byte[] car = new byte[1024];
int len = is.read(car);
System.out.println(new String(car,0,len));
//4.关闭
is.close();
os.close();
client.close();
}
}
public class TCPServer04 {
public static void main(String[] args) throws IOException {
System.out.println("---------------Server--------------");
//1.创建服务端
ServerSocket server = new ServerSocket(8888);
//2.阻塞式监听
Socket client = server.accept();
System.out.println("-----------有一个客户端连接成功-------------------");
//3.获取IO流
InputStream is = client.getInputStream();
//4.读入数据
byte[] car = new byte[1024];
//把数据读入到字节数组car中,返回值len为读入到字节数组中真实数据的长度
int len = is.read(car);
String name =null;
String pwd =null;
//5.操作数据
String str = new String(car,0,len);
//分割数据 name=laopei&pwd=0523
String[] arr = str.split("&");
for(String s:arr) {
String[] ss = s.split("=");
//判断当前这个ss[1]是名字的值还是密码的值
if("name".equals(ss[0])) {
name = ss[1];
}else {
pwd = ss[1];
}
}
System.out.println(name);
System.out.println(pwd);
//获取输出流
OutputStream os = client.getOutputStream();
//校验
if("laopei".equals(name) && "0523".equals(pwd)) {
os.write("登录成功".getBytes());
}else {
os.write("shibai".getBytes());
}
os.flush();
//6.关闭
os.close();
is.close();
client.close();
server.close();
}
}