网络编程和多线程
多线程
为什么要有多线程呢?
线程是操作系统能够进行运算调度的最小单元。它被包含在进程之中,是进程的实际运作单位。
什么是多线程?
应用软件中互相独立,可以同时运行的功能。
多线程的作用?
提高效率
多线程的场景?
软件中的耗时操作,所有的聊天软件,所有的服务器。
多线程的两个概念
并发:在同一时刻,有多个指令在同一个CPU上运行。
并行:在同一时刻,有多个指令在多个CPU上运行。
多线程的实现方式
第一种实现方式:
java
package Thread_learn;
public class MyThread extends Thread{
//重写run方法 方法中的代码就是线程要执行的内容
@Override
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "hello world");
}
}
}
public class test {
public static void main(String[] args) {
//创建一个线程对象
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
// 给线程取个名字
myThread1.setName("线程1");
myThread2.setName("线程2");
// 开启一个线程
myThread1.start();
myThread2.start();
}
}
第二种实现方式:
java
// 继承Runnable
public class MyThread1 implements Runnable{
@Override
public void run(){
for (int i = 0; i < 10; i++) {
//获取当前线程对象
Thread t1 = Thread.currentThread();
System.out.println(t1.getName() + "hello world");
}
}
}
java
public class test1 {
public static void main(String[] args) {
//创建一个对象
MyThread1 myThread1 = new MyThread1();
MyThread1 myThread2 = new MyThread1();
//把对象传给线程
Thread t1 = new Thread(myThread1);
Thread t2 = new Thread(myThread2);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
第三种实现方式:
特点:可以有返回值
java
public class MyThread2 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for(int i =1;i <= 100;i++){
sum += i;
}
return sum;
}
}
public class test2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建一个实现了Callable接口的类的对象
MyThread2 myThread2 = new MyThread2();
//创建一个FutureTask对象,来管理Callable对象(管理多线程运行的结果)
FutureTask<Integer> ft = new FutureTask<Integer>(myThread2);
//创建一个Thread对象,并启动
Thread t1 = new Thread(ft);
//启动这个线程
t1.start();
//获取线程运行结果
System.out.println(ft.get());
}
}
三种线程的对比
thread:
优点:代码操作简单
缺点:没有返回值,扩展性差,不能再继承其它的类
实现Runnable接口,Callable接口:
扩展性强,实现刻接口还可以继承其它类,
编程相对复杂,不能直接使用Thread类中的方法。
常见的成员方法

java
// Thread t1 = new Thread(new Runnable(){
// @Override
// public void run() {
// for (int i = 0; i < 10; i++) {
// // 得到当前线程对象
// System.out.println(Thread.currentThread().getName() +"@"+"hello world");
// }
// }
// });
//
//
//
// t1.start();
//
// System.out.println(t1.getName());
System.out.println(1111111);
//让当前线程休眠m毫秒
Thread.sleep(1000);
System.out.println(222222);
//获取当前线程对象
System.out.println(Thread.currentThread());
// 通过构造方法设置线程名称
Thread t1 = new Thread("线程1");
System.out.println(t1.getName());
java
MyRunnable runnable1 = new MyRunnable();
MyRunnable runnable2 = new MyRunnable();
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t1.setName("飞机");
t2.setName("坦克");
//设置线程优先级
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
//特到线程的优先级
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
当所有的非守护线程结束之后,守护线程就会被立即终止。
java
package demo1;
import Thread_learn.MyThread1;
public class demo2 {
public static void main(String[] args) {
MyRunnable runnable1 = new MyRunnable();
MyThread1 runnable2 = new MyThread1();
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t2.setName("坦克");
t1.setName("飞机");
// //设置线程优先级
// t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
//守护线程在其它非守护线程执行完毕之后,也会陆续结束。
//把第一个线程设置为守护线程
t1.setDaemon(true);
t1.start();
t2.start();
}
}
package Thread_learn;
// 继承Runnable
public class MyThread1 implements Runnable{
@Override
public void run(){
for (int i = 0; i < 10; i++) {
//获取当前线程对象
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Thread t1 = Thread.currentThread();
System.out.println(t1.getName() + "hello world");
}
}
}
package demo1;
public class MyRunnable implements Runnable{
@Override
public void run(){
for (int i = 0; i < 100; i++) {
// 获取当前线程对象
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + " " +i);
}
}
}
礼让线程
java
//执行到当前线程的时候,把当前线程让出去,所以线程重新抢执行权
Thread.yield();
插入线程:
java
MyRunnable runnable1 = new MyRunnable();
Thread t1 = new Thread(runnable1);
t1.setName("土豆");
t1.start();
//礼让线程
//表示把t这个线程,插入到当前线程之前
t1.join();
for (int i = 0; i < 10; i++) {
System.out.println("main线程"+i);
}
线程的生命周期

线程安全的问题
遇到的问题
java
package demo1;
public class MyRunnable implements Runnable{
static int ticket = 0;
@Override
public void run(){
while(true){
if(ticket < 100){
ticket++;
System.out.println(Thread.currentThread().getName() + "正在抢第" +ticket+"张票!!!");
}else{
break;
}
}
}
}
package demo1;
public class demo4 {
public static void main(String[] args) {
MyRunnable myRunnable1 = new MyRunnable();
MyRunnable myRunnable2 = new MyRunnable();
MyRunnable myRunnable3 = new MyRunnable();
Thread t1 = new Thread(myRunnable1);
Thread t2 = new Thread(myRunnable2);
Thread t3 = new Thread(myRunnable3);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
打印结果:
窗口2正在抢第2张票!!!
窗口2正在抢第4张票!!!
窗口3正在抢第3张票!!!
窗口1正在抢第1张票!!!
窗口3正在抢第6张票!!!
窗口2正在抢第5张票!!!
窗口3正在抢第8张票!!!
窗口1正在抢第7张票!!!
窗口3正在抢第10张票!!!
窗口2正在抢第9张票!!!
窗口3正在抢第12张票!!!
窗口1正在抢第11张票!!!
窗口3正在抢第14张票!!!
窗口2正在抢第13张票!!!
窗口3正在抢第16张票!!!
窗口1正在抢第15张票!!!
窗口3正在抢第18张票!!!
窗口2正在抢第17张票!!!
窗口3正在抢第20张票!!!
窗口1正在抢第19张票!!!
窗口3正在抢第22张票!!!
窗口2正在抢第21张票!!!
窗口3正在抢第24张票!!!
窗口1正在抢第23张票!!!
窗口3正在抢第26张票!!!
窗口2正在抢第25张票!!!
窗口1正在抢第27张票!!!
窗口3正在抢第28张票!!!
窗口1正在抢第30张票!!!
窗口2正在抢第29张票!!!
窗口1正在抢第32张票!!!
窗口3正在抢第31张票!!!
窗口1正在抢第34张票!!!
窗口2正在抢第33张票!!!
窗口1正在抢第36张票!!!
窗口3正在抢第35张票!!!
窗口1正在抢第38张票!!!
窗口2正在抢第37张票!!!
窗口3正在抢第39张票!!!
窗口1正在抢第40张票!!!
窗口2正在抢第41张票!!!
窗口1正在抢第43张票!!!
窗口3正在抢第42张票!!!
窗口1正在抢第45张票!!!
窗口2正在抢第44张票!!!
窗口1正在抢第47张票!!!
窗口3正在抢第46张票!!!
窗口1正在抢第49张票!!!
窗口3正在抢第50张票!!!
窗口2正在抢第48张票!!!
窗口3正在抢第52张票!!!
窗口1正在抢第51张票!!!
窗口1正在抢第55张票!!!
窗口3正在抢第54张票!!!
窗口2正在抢第53张票!!!
窗口3正在抢第57张票!!!
窗口1正在抢第56张票!!!
窗口3正在抢第59张票!!!
窗口2正在抢第58张票!!!
窗口3正在抢第61张票!!!
窗口1正在抢第60张票!!!
窗口3正在抢第63张票!!!
窗口2正在抢第62张票!!!
窗口3正在抢第65张票!!!
窗口1正在抢第64张票!!!
窗口3正在抢第67张票!!!
窗口2正在抢第66张票!!!
窗口2正在抢第70张票!!!
窗口3正在抢第69张票!!!
窗口1正在抢第68张票!!!
窗口3正在抢第72张票!!!
窗口3正在抢第74张票!!!
窗口3正在抢第75张票!!!
窗口2正在抢第71张票!!!
窗口3正在抢第76张票!!!
窗口1正在抢第73张票!!!
窗口1正在抢第79张票!!!
窗口1正在抢第80张票!!!
窗口3正在抢第78张票!!!
窗口2正在抢第77张票!!!
窗口3正在抢第82张票!!!
窗口1正在抢第81张票!!!
窗口3正在抢第84张票!!!
窗口2正在抢第83张票!!!
窗口3正在抢第86张票!!!
窗口1正在抢第85张票!!!
窗口3正在抢第88张票!!!
窗口2正在抢第87张票!!!
窗口3正在抢第90张票!!!
窗口1正在抢第89张票!!!
窗口3正在抢第92张票!!!
窗口2正在抢第91张票!!!
窗口2正在抢第95张票!!!
窗口2正在抢第96张票!!!
窗口2正在抢第97张票!!!
窗口3正在抢第94张票!!!
窗口1正在抢第93张票!!!
窗口3正在抢第99张票!!!
窗口2正在抢第98张票!!!
窗口1正在抢第100张票!!!
我在学习多线程中的同步代码块 这个我还没用锁 我只是想看一下多线程会出现的问题
为什么票数小的可能会出现在票数大的
虽然说执行权在任意时刻都可能会被其它线程抢走
但是这个ticket是静态的呀 如果被抢走了 其它线程执行了ticket++ 那么的话当再被抢回来的时候 执行打印语句的时候,不应该是被++之后的ticket吗 怎么输出的还是被抢走之前的ticket
解答:
ticket++分为三步:
int temp = ticket;
temp = temp + 1;
ticket = temp;
应为执行权在任意时刻都可能被抢夺 所以可能就是在第二步的时候被抢走了执行权,在当被的线程执行完之后,当前线程就执行第三步,就会把之前的值给覆盖掉。
java
static int ticket = 0;
@Override
public void run(){
while(true){
synchronized(MyRunnable.class){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(ticket < 100){
ticket++;
System.out.println(Thread.currentThread().getName() + "正在抢第" +ticket+"张票!!!");
}else{
break;
}
}
}
}
同步代码块的细节:
1.synchronized需要写在循环的内部
2.传入的锁对象必须是同一个对象
同步方法:是锁方法里面所有的代码
把共享的代码抽取成一个方法,方法用synchronized来修饰,jvm会自动指定锁对象
静态方法的锁对象是当前类的字节码文件对象。非静态的是this
lock锁 :
提供获取锁和释放锁的方法
void lock():获取锁
void unlock():释放锁
lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化。
java
package demo1;
import java.util.concurrent.locks.ReentrantLock;
public class MyRunnable implements Runnable{
static int ticket = 0;
static ReentrantLock lock = new ReentrantLock();
@Override
public void run(){
while(true){
lock.lock();
try{
Thread.sleep(10);
if(ticket < 100){
ticket++;
System.out.println(Thread.currentThread().getName() + "正在抢第" +ticket+"张票!!!");
}else{
break;
}
}catch(InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
}
}
}
死锁
由于锁的嵌套 导致死锁,导致程序不会终止。
生产者和消费者


线程池
开始的时候不会创建线程 会根据具体的任务创建线程
如果是限制了线程数量 并且有多个任务 线程不够用的时候就只能排队
java
package demo4;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.*;
public class test {
public static void main(String[] args) {
// 创建线程池对象 -- 几乎没有上限的线程数 -- 线程空闲的60s会自动销毁
ExecutorService pool = Executors.newCachedThreadPool();
//获取线程池对象 -- 可以设置线程数量 -- 不会自动销毁
// ExecutorService pool = Executors.newFixedThreadPool(3);
//提交任务
pool.submit(new MyThread());
pool.submit(new MyThread());
pool.submit(new MyThread());
pool.submit(new MyThread());
pool.submit(new MyThread());
//摧毁线程池
pool.shutdown();
}
}
自定义线程池


网络编程
什么是网络编程



网络编程三要素
ip: 设备在网络中的地址,是唯一的标识
端口号:应用程序在设备中唯一的标识
协议:数据在网络中传输的规则,常见的协议有UDP,TCP,http,https,ftp.
ip


ping 网址/ip地址
java
// 确认主机名称的ip地址,主机名称可以是域名,也可以是ip地址
//一台电脑的对象
InetAddress address = InetAddress.getByName("Hou");
System.out.println(address);
//获取ip地址
System.out.println(address.getHostAddress());
//获取主机名(如果没有这个主机 那么返回的就是ip地址)
System.out.println(address.getHostName());
端口号

UDP通信程序
用户数据报协议:不需要确保网络是否连通
udp是面向无连接的通信协议:
特点:速度快,有大小限制,数据不安全,容易丢失数据。
应用场景:在线视频,语音通话
发送数据
java
/*
* 细节:
* 绑定端口号,以后通过这个端口号往外发送信息
* 空参:所有可以用的端口号中随机抽取一个进行使用
* 有参:指定端口号进行绑定
* */
//创建对象
DatagramSocket ds = new DatagramSocket();
//需要发送的信息
String info = "你好呀!!!";
byte[] bytes = info.getBytes();
//获取ip
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10086;
//打包
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
//发送数据
ds.send(dp);
//释放资源
ds.close();
接收数据
java
//创建对象
DatagramSocket ds = new DatagramSocket(10086);
//创建接受数据的数组
byte[] bytes = new byte[1024];
//创建接受数据包
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
//接受数据(是阻塞的 直到接受到数据)
ds.receive(dp);
//释放资源
ds.close();
//打印接受到的数据
System.out.println("接受到的数据: "+new String(dp.getData(),0,dp.getLength()));
System.out.println("来自"+dp.getAddress().getHostAddress()+"的"+dp.getPort());
细节:接收数据的代码必须先运行
UDP的三种通信方式
单播:将数据包发送给特定的一个主机
组播:将数据包发送给特定组主机
组播的地址:224.0.0.0 - 239.255.255.255
其中224.0.0.0- 224.0.0.255为预留的组播地址
广播:将数据包发送给局域网内所有的主机
组播代码实现:
java
public static void main(String[] args) throws IOException {
// 创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket();
//创建数据
String str = "你好呀!!!";
byte[] bytes = str.getBytes();
//获取主机
InetAddress address = InetAddress.getByName("224.0.0.1");
//设定端口
int port = 10086;
//创建数据包
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
//发送信息
ms.send(dp);
//释放资源
ms.close();
}
java
public static void main(String[] args) throws IOException {
//创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket(10086);
//加入组播
InetAddress address = InetAddress.getByName("224.0.0.2");
ms.joinGroup(address);
//创建数据包对象 来接收数据
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
ms.receive(dp);
ms.close();
System.out.println("接受到的数据: "+new String(dp.getData(),0,dp.getLength()));
System.out.println("来自: "+dp.getAddress().getHostAddress()+":"+dp.getPort());
}
广播代码实现:
和组播的区别就是ip地址为"255.255.255.255"
java
public static void main(String[] args) throws IOException {
// 创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket();
//创建数据
String str = "你好呀!!!";
byte[] bytes = str.getBytes();
//获取主机
InetAddress address = InetAddress.getByName("255.255.255.255");
//设定端口
int port = 10086;
//创建数据包
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
//发送信息
ms.send(dp);
//释放资源
ms.close();
}
TCP通信程序
传输控制协议:需要确保网络连通
tcp协议是面向连接的通信协议
特点:速度慢,没有大小控制,数据安全。
应用场景:软件下载,发送邮件

三次握手 四次挥手
三次握手:

四次挥手:

放射
放射的概念
放射允许对封装的字段,方法,和构造函数的信息进行编程访问
三种获取class对象的方法
java
//全类名 : 包名 + 类名
//最为常用
// Class clazz = Class.forName("getClass_demo.Student");
Class clazz = Class.forName("getClass_demo.Student");
System.out.println(clazz);
//第二种方式 主要是作为参数传递
Class clazz2 = Student.class;
System.out.println(clazz);
//第三种方式
//当我们已经有了这个类的对象是,才能使用
Student student = new Student();
Class clazz3 = student.getClass();
System.out.println(clazz);
放射获取构造方法

java
//获取所有公共的构造方法
Constructor<Student>[] clazz = (Constructor<Student>[]) Class.forName("getClass_demo.Student").getConstructors();
for(Constructor<Student> c : clazz){
System.out.println(c);
}
//获取所有的构造方法
Constructor<Student>[] clazz1 = (Constructor<Student>[]) Student.class.getDeclaredConstructors();
for(Constructor<Student> c : clazz1){
System.out.println(c);
}
//获取公共的构造方法
// Constructor<Student> clazz2 = (Constructor<Student>) Class.forName("getClass_demo.Student").getConstructor(String.class,int.class,String.class);
// System.out.println(clazz2);
// 获取任意一个构造方法
Constructor<Student> clazz3 = (Constructor<Student>) Class.forName("getClass_demo.Student").getDeclaredConstructor(String.class,int.class,String.class);
System.out.println(clazz3);
//获取访问权限
System.out.println(clazz3.getModifiers());
//获取参数列表
Parameter[] pt = clazz3.getParameters();
for(Parameter p : pt){
System.out.println(p);
}
//设置取消权限修饰符效验
clazz3.setAccessible(true);
//创建学生对象
Student s = clazz3.newInstance("张三",18,"男");
System.out.println(s);
放射获取成员变量
java
// Class clazz = Class.forName("getClass_demo.Student");
// //获取成员变量
// Field[] field = clazz.getFields();
// for(Field f : field){
// System.out.println(f);
// }
// //获取所有的成员变量
// Field[] field1 = clazz.getDeclaredFields();
//
// for(Field f : field1){
// System.out.println(f);
// }
// //获取公开的成员变量
// Field gender = clazz.getField("gender");
// System.out.println(gender);
//
// Class clazz = Student.class;
Student s = new Student();
Class clazz = s.getClass();
//获取所有权限修饰的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);
name.setAccessible(true);
//给变量赋值
name.set(s,"zhangsan");
System.out.println(s);
//获取变量名称
System.out.println(name.getName());
//得到变量的值
System.out.println(name.get(s));
放射获取成员方法

java
Class clazz = Class.forName("getClass_demo.Student");
// 返回所有公共成员方法的数组,包括继承的
// Method[] methods = clazz.getMethods();
// for(Method m : methods){
// System.out.println(m);
// }
//返回所有的成员方法,不包括继承的
// Method[] methods1 = clazz.getDeclaredMethods();
// for(Method m : methods1){
// System.out.println(m);
// }
Student s = new Student();
Method m = clazz.getMethod("eat", String.class);
//获取参数列表
Parameter[] pt = m.getParameters();
for(Parameter p : pt){
System.out.println(p);
}
//调用方法
m.invoke(s,"苹果");
Class[] exceptionTypes = m.getExceptionTypes();
for(Class c : exceptionTypes){
System.out.println(c);
}
反射的作用

动态代理

创建一个接口,把需要代理的方法都写到里面,代理和原对象都需要实现些方法。

java
package dp_demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
//创建代理对象
public static Star getProxy(BigStar bigstar){
Star star = (Star) Proxy.newProxyInstance(
//第一个参数: 用于获取指定的类加载器,去加载生成的代理类
ProxyUtil.class.getClassLoader(),
//第二个参数:用于获取代理需要实现的接口
new Class[]{Star.class},
//第三个参数:用来指定代理需要做的事情
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 参数一 : 代理的对象
// 参数二 : 要运行的方法
// 参数三 : 调用方法需要传入的实参
if(method.getName().equals("sing")){
System.out.println("准备话筒,收钱");
}else if(method.getName().equals("dence")){
System.out.println("准备场地,收钱");
}
return method.invoke(bigstar,args);
}
}
);
return star;
}
}
java
package dp_demo;
public class BigStar implements Star{
private String name;
public BigStar() {
}
public BigStar(String name) {
this.name = name;
}
@Override
public String sing(String sing_name){
System.out.println(name+"正在唱:"+sing_name);
return "谢谢";
}
@Override
public void dence(String dance_name){
System.out.println(name+"正在跳舞:"+dance_name);
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
public String toString() {
return "BigStar{name = " + name + "}";
}
}
java
package dp_demo;
public interface Star {
public abstract String sing(String sing_name);
public abstract void dence(String dance_name);
}
java
package dp_demo;
public class test {
public static void main(String[] args) {
BigStar bigstar = new BigStar("周杰伦");
Star star = ProxyUtil.getProxy(bigstar);
String result = star.sing("七里香");
System.out.println(result);
}
}