线程
线程优先级
提高线程优先执行的可能
1~10 1最小 10最大 默认时5
setPriority(int newPriority) 改变这个线程的优先级。
static int MAX_PRIORITY //一个线程可以拥有的最高优先级。
static int MIN_PRIORITY // 一个线程可以拥有的最低优先级。
static int NORM_PRIORITY // 分配给线程的默认优先级。
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());
}
}
线程死锁
死锁及解决方案
class Lipstick{
}
class Mirror{
}
class Makeup extends Thread {
int flag;
String girl;
static Lipstick lipstick=new Lipstick();
static Mirror mirror= new Mirror();
@Override
public void run() {
doMakeup();
}
void doMakeup(){
if(flag==0){
synchronized (lipstick) {
System.out.println(girl+"拿着口红!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (mirror) {
System.out.println(girl+"拿着镜子!");
}
}
}else{
synchronized (mirror) {
System.out.println(girl+"拿着镜子!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lipstick) {
System.out.println(girl+"拿着口红!");
}
}
}
}
}
public class TestDeadLock {
public static void main(String[] args) {
Makeup m1 = new Makeup();
m1.girl="大丫";
m1.flag=0;
Makeup m2 = new Makeup();
m2.girl="小丫";
m2.flag=1;
m1.start();
m2.start();
}
}
如何解决死锁问题:
-
往往是程序逻辑的问题。需要修改程序逻辑。
-
尽量不要同时持有两个对象锁。 如修改成如下:
void doMakeup(){
if(flag==0){
synchronized (lipstick) {
System.out.println(girl+"拿着口红!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (mirror) {
System.out.println(girl+"拿着镜子!");
}
else{
synchronized (mirror) {
System.out.println(girl+"拿着镜子!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (lipstick) {
System.out.println(girl+"拿着口红!");
}
}
}
}
线程通信
生产者消费者模式
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();
}
}
}
网络编程
网络编程:
- 如何定位到一台电脑 IP(如人的身份证号码)
- 如何区分多个软件 (端口)
- 如何区分一个软件中的多个资源 url
IP位置
使用方法
InetAddress.getLocalHost();返回本地主机的地址
InetAddress.getByName("www.163.com");决定了IP地址的主机,主机的名字
InetAddress.getByName("223.87.1.58");决定了IP地址的主机,主机的名字
getHostAddress() 返回 ip 地址
getHostName() 返回域名|本机为计算机名
示例:
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)
端口是虚拟的概念,并不是说在主机上真的有若干个端口。通过端口,可以在一个主机上运行多个网络应用程序。
注意:
-
同一个协议下端口号不能冲突
-
8000以下的端口号不建议使用–>预留端口号
常见的端口号:
80 http
8080 tomcat
3306 mysql
1521 oracle
InetSocketAddress 端口类(ip+端口)
//获取对象
InetSocketAddress(String hostname, int port)
InetSocketAddress(InetAddress addr, int port)
//方法
getAddress() 返回 InetAddress 对象
getPort() 返回端口
getHostName() 返回域名
示例:
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());
}
}
网络爬虫原理
简单爬虫
package com.xxxx.net02;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
/*
* 爬虫
*/
public class SpiderDemo04{
public static void main(String[] args) throws IOException {
//1.URL
URL url = new URL("http://www.baidu.com");
//2.获取流(输入流)
InputStream is = url.openStream();
//通过InputStreamReader 把字节流转换成为字符流
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
//3.读入
String str=null;
while((str=rd.readLine())!=null) {
System.out.println(str);
}
//4.关闭
rd.close();
is.close();
}
}
协议
UDP协议
非面向连接 不安全 效率高 协议简单 开销小 大小有限一般不超过60k—>发送端和接受端两端平等 ---->字节数组
**UDP实现基本流程: 发送端 **
- 定义发送端 DatagramSocket(int port) 指定发送端ip和端口
- 准备数据–> 转为字节数组
- 打包 DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造一个数据报包发送数据包的长度 length抵消 ioffsetto指定主机上的指定端口号。
- 发送数据 send(DatagramPacket p) 从这个套接字发送一个数据报包。
- 关闭
示例:
package com.xxxx.net03;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
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实现基本流程: 接收端
- 构建接收端
- 准备包裹–>用来接收数据
- 接收
- 处理数据
- 关闭
示例
package com.xxxx.net03;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
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();
}
}
TCP协议
面向连接 安全、可靠 效率低 基于IO流操作
Socket 套接字:
相当于传输层为应用层开辟的一个小口子
不同协议下Socket实现不同
面向Socket编程
TCP 基本流程: 客户端
- 创建客户端 Socket(String host, int port) 指定服务端的IP+端口
- 获取IO流
- 写出数据
- 关闭
示例:
package com.xxxx.net03;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPClient03 {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("---------------client--------------");
//1.创建客户端
Socket client = new Socket("127.0.0.1",8888);
//2.获取输入流
OutputStream is = client.getOutputStream();
//3.写出数据
is.write("zhangsan".getBytes());
//4.关闭
is.close();
client.close();
}
}
TCP 基本流程: 服务端
- 创建服务端 ServerSocket(int port) 创建绑定到特定端口的服务器套接字。 服务端的端口号
- 阻塞式监听
- 获取IO流
- 读入数据
- 操作数据
- 关闭
示例:
package com.xxxx.net03;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
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);
//5.操作数据
System.out.println(new String(car,0,len));
//6.关闭
is.close();
client.close();
server.close();
}
}