Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程

news2024/9/23 1:23:45

导学了解

什么是进程?

进程:程序的基本执行实体

更加通俗的讲:一个软件执行后,它就是一个进程,绿色的内容都是一个进程。

什么是线程?

线程是操作系统能够进行运算调度的最小单位。它被包含在进程当中,是进程中的实际运作单位。

可以这样理解: 用没有用过360安全卫士,它上面的每个功能都相当于进程,很多进程能够同时的运行,并且互相没有产生问题。进程类似于应用中互相独立,可以同时运行的功能。很多的线程合在一起就形成了多线程。

什么是多线程?

Java多线程是指在Java程序中同时运行多个线程,每个线程都可以独立执行不同的任务。Java多线程可以提高程序的并发性和响应性,使得程序可以同时处理多个任务,提高程序的效率。Java中的多线程可以通过继承Thread类或实现Runnable接口来创建线程,也可以使用线程池来管理线程。同时,Java提供了丰富的多线程API,如synchronized关键字、wait()和notify()方法等,来帮助开发者更好地控制线程的并发访问。

实现多线程的三种方式:

方法一:继承Thread类:

通过重写父类Thread方法中的run方法实现线程

注意:线程的开启是通过使用start方法来开启线程,而并非是通过使用调用run方法,通过类的对象去调用run方法,只能是一个普通的调用,并不能开启线程。

代码实现: 

package thread_study;

public class demo1 {
    public static void main(String[] args) {
        MyThread1 thread = new MyThread1();
        MyThread1 thread2 = new MyThread1();
        thread.setName("线程一");
        thread2.setName("线程而");
        //注意:这里的线程开发则是通过start方法去开启,并非是通过调用run方法,调用run方法则是普通的调用
        thread.start();
        thread2.start();

    }
}
class MyThread1 extends Thread{
    /*
        开启线程的第一种方法:
        定义个类去继承线程类Thread
        重写类中的run方法
        创建子类的对象,并且去开启线程
     */
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println("这是"+getName()+"的内容输出");
        }
    }
}

控制台输出:

方法二:通过实现Runnable接口

代码实现

package thread_study;

public class demo2 {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        Thread thread = new Thread(myThread2);
        Thread thread2 = new Thread(myThread2);
        thread.setName("线程一");
        thread2.setName("线程二");
        thread.start();
        thread2.start();

    }
}
class MyThread2 implements Runnable{
    /*
        开启线程的第二种方法:
        定义个类实现R
        重写类中的run方法
        创建子类的对象,并且去开启线程
     */
    @Override
    public void run() {
        for (int i=0;i<10;i++){
//            Thread thread = Thread.currentThread();
            System.out.println("这是"+Thread.currentThread().getName()+"的内容输出");
        }
    }
}

方法三:继承Callable

注意:这个方法拥有返回值

package thread_study;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//第三种方法去实现线程
public class MyThread3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
            多线程实现的第三种方法:可以接收到线程运行的结果
            通过实现Callable接口,重写call方法
            然后通过创建FutureTask对象(通过此类可以实现对多线程运行结果的管理
         */
        MyThread_test myThread_test = new MyThread_test();
        FutureTask<Integer> futureTask  = new FutureTask<>(myThread_test);
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());

    }

}
class MyThread_test implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i <= 100; i++) {
            sum =sum +i;
        }
        return sum;
    }
}

多线程常用的方法讲解 

setPriorit(int 值):设置优先级

可以设置线程的优先顺序,优先级高的线程会优先去执行,但是这种方法的设置,并不意味着优先级高的一定比优先级底的先执行完,因为在线程执行是抢占式,谁先抢到谁先去执行,所以说优先级高的并不是一定的比线程优先级低的先行执行完成。

代码实现:

设置:线程二的优先级比线程的一的优先级高

package thread_study;

public class MyThread04 {
    public static void main(String[] args) {
        Thread04_test thread04_test= new Thread04_test();
        Thread thread = new Thread(thread04_test,"线程一");
        Thread thread2 = new Thread(thread04_test,"线程二");
        //获取当前线程的优先级
//        System.out.println(Thread.currentThread().getPriority());
        //设置进程的优先级默认为5 1最小 10最大
        thread.setPriority(1);
        thread2.setPriority(10);
        thread.start();
        thread2.start();
    }
}
class Thread04_test implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"@"+i);
        }
    }
}
/*
* 线程优先级低的可能比优先级的高的线程先行执行完,只是这中的概率比较低,但是还是有一种概率发生。如果不进行任何的设置,那么这个线程的默认优先级数值为5
*
* */

运行结果:

大概率的情况下:线程二先行执行完,然后线程一再执行完

小概率的情况下:线程二后执行完,线程一先行执行完

守护线程

守护线程:可以理解为当一个线程结束时,守护线程也会陆续的结束 ,qq聊天界面,有着聊天和传输文件的功能,聊天是一个线程,传输文件也是一个线程,但是当一个qq聊天界面关闭时,那么传输文件的哪个界面,也就关闭了 * 守护线程当线程结束时,那么守护线程则没有没有存在的必要了,但是它不会立刻的结束,他会慢慢的结束。

案例实现线程二对线程一的守护,当线程一结束时,他的守护线程二也会陆陆续续的停掉

代码实现: 

package thread_study;

public class MyThread05 {
    public static void main(String[] args) {
        /*
        *   守护线程:可以理解为当一个线程结束时,守护线程也会陆续的结束
        *   qq聊天界面,同时聊天和传输文件,聊天是一个线程,传输文件也是一个线程,但是当一个qq聊天界面关闭时,那么传输文件的哪个界面,也就关闭了
        *   守护线程当线程结束时,那么守护线程则没有没有存在的必要了,但是它不会立刻的结束,他会慢慢的结束
        *
        * */
        //案例实现线程二对线程一的守护,当线程一结束时,他的守护线程二也会陆陆续续的停掉
        Thread05_demo1 thread05_demo1 = new Thread05_demo1();
        Thread05_demo2 thread05_demo2 = new Thread05_demo2();

        thread05_demo1.setName("线程一");
        thread05_demo2.setName("线程二");
        //把线程二设置成守护线程
        thread05_demo2.setDaemon(true);

        thread05_demo1.start();
        thread05_demo2.start();
    }
}

class Thread05_demo1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}
class Thread05_demo2 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

运行结果:

线程二守护线程一,当线程一执行完之后,线程二就陆陆续续的结束,并不能直接的结束

 yield()出让线程

出让线程:Java的线程时抢占式,多线程过程中,谁先抢到线程,谁就会先执行 *

也可以通过yield出让本线程的执行权,出让执行权,但是出让这个机会,出让执行权的线程依旧可以再次的抢夺,可以通过此方法实现尽可能的均匀 *

静态方法,可以通过类去直接的调用

代码实现

package thread_study;

public class MyThread06 {
    public static void main(String[] args) {
        /*
        * 出让线程:Java的线程时抢占式,多线程过程中,谁先抢到线程,谁就会先执行
        * 也可以通过yield出让本线程的执行权,出让执行权,但是出让这个机会,出让执行权的线程依旧可以再次的抢夺,可以通过此方法实现尽可能的均匀
        * 静态方法,可以通过类去直接的调用
        * */
        MyThread06_test myThread06_test1 = new MyThread06_test();
        MyThread06_test myThread06_test2 = new MyThread06_test();

        myThread06_test1.setName("线程一");
        myThread06_test2.setName("线程二");

        myThread06_test1.start();
        myThread06_test2.start();
    }
}

class MyThread06_test extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
            //出让当前CPU的执行权
            Thread.yield();
        }
    }
}

join方法:实现线程的插入(通俗的讲就是插队)

插入线程,在一个线程的前面,在插入一个线程

通过join方法来实现

main方法默认的情况下也是一个程序

在main方法去执行程序,然后再通过join方法去再main方法前添加一个程序

代码实现

package thread_study;

public class MyThread07 {
    public static void main(String[] args) throws InterruptedException {
        /*
            插入线程,在一个线程的前面,在插入一个线程
            通过join方法来实现
            main方法默认的情况下也是一个程序
            在main方法去执行程序,然后再通过join方法去再main方法前添加一个程序
        * */
//      通过join方法实现MyThread07_test线程的插入
        MyThread07_test myThread07_test = new MyThread07_test();
        myThread07_test.setName("线程");
        myThread07_test.start();
        myThread07_test.join();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }

}

class MyThread07_test extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

运行结果

线程插队成功

锁:synchronized

//同步代码块

//给线程添加一个锁,保证的是只有一个线程去执行,当代码完全执行完毕后,再释放锁,不会出现数据的重复,和超出范围值

//注意锁的对象必须是唯一的,可以通过字节码对象,因为带idea中类的创建必须是唯一的

* 实现三个售票点,正在销售,总共有100张票

* 在正常的开发过程中,几个线程同时执行代码,那么在同一时间而言,就有可能有多个线程去执行同一行代码

* 这样就容易出现代码的重复,还会容易出现,超出范围等问题,锁的产生帮助我们去解决这个问题 

 代码实现

package thread_study;

public class MyThread08 {

    public static void main(String[] args) {
        /*
        * 实现三个售票点,正在销售,总共有100张票
        * 在正常的开发过程中,几个线程同时执行代码,那么在同一时间而言,就有可能有多个线程去执行同一行代码
        * 这样就容易出现代码的重复,还会容易出现,超出范围等问题,锁的产生帮助我们去解决这个问题
        * */

        MyThread08_test myThread08_test1 = new MyThread08_test();
        MyThread08_test myThread08_test2 = new MyThread08_test();
        MyThread08_test myThread08_test3 = new MyThread08_test();

        myThread08_test1.setName("售票点一");
        myThread08_test2.setName("售票点二");
        myThread08_test3.setName("售票点三");

        myThread08_test1.start();
        myThread08_test2.start();
        myThread08_test3.start();

    }


}

class MyThread08_test extends Thread{
    static int ticket = 1;
    @Override
    public void run() {
        while (true){
            //同步代码块
            //给线程添加一个锁,保证的是只有一个线程去执行,当代码完全执行完毕后,再释放锁,不会出现数据的重复,和超出范围值
            //注意锁的对象必须是唯一的,可以通过字节码对象,因为带idea中类的创建必须是唯一的
            synchronized (MyThread08_test.class){
                if(ticket<=100){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "正在卖第"+ticket +"票");
                    ticket ++;
                }else {
                    break;
                }
            }
        }
    }
}

输出结果:

把synchronized关键字定义在方法上如何的实现

代码实现

package thread_study;

public class MyThread09 {
    public static void main(String[] args) {
        MyThread09_test myThread09_test = new MyThread09_test();
        Thread thread1 = new Thread(myThread09_test);
        Thread thread2 = new Thread(myThread09_test);
        Thread thread3 = new Thread(myThread09_test);

        thread1.setName("窗口一");
        thread2.setName("窗口二");
        thread3.setName("窗口三");

        thread1.start();
        thread2.start();
        thread3.start();
    }

}

class MyThread09_test implements Runnable{
    int ticket = 1;

    @Override
    public void run() {
        while (true){
            try {
                if (demo1()) break;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized boolean demo1() throws InterruptedException {
        if(ticket>100){
            return true;
        }else{
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + "正在卖第" +ticket + "票");
            ticket ++;
        }
        return false;
    }
}

锁二:Lock

synchronized:这个上锁是自动化,只要有线程执行了方法,就会上锁,但是只有当方法完全之后,才要释放锁

通过lock来实现,上锁和释放锁,通过我们的手动的方法去上锁和释放锁,并非像synchronized智能锁一样不需要手动的添加。

通过Lock方法实现上一个卖票的案例

package thread_study;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyThread10 {
    public static void main(String[] args) {
        /*
        * synchronized:这个上锁是自动化,只要有线程执行了方法,就会上锁,但是只有当方法完全之后,才要释放锁
        * 通过lock来实现,上锁和释放锁
        * */
        MyThread10_test myThread10_test = new MyThread10_test();
        Thread thread = new Thread(myThread10_test);
        Thread thread2 = new Thread(myThread10_test);
        Thread thread3 = new Thread(myThread10_test);
        thread.setName("线程1");
        thread2.setName("线程2");
        thread3.setName("线程3");
        thread.start();
        thread2.start();
        thread3.start();
    }
}
class MyThread10_test implements Runnable{
    static int ticket = 1;
    static Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            //上锁
            lock.lock();
            try {
                if(ticket<=100){
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + "正在卖第"+ticket +"票");
                    ticket ++;

                }else {
                    break;
                }
                
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {   //把释放锁放在finally可以确保,无论如何释放锁都会被执行
                //释放锁
                lock.unlock();
                
            }
        }
    }
    }

等待唤醒机制:生产者和消费者机制

这种模式是一种十分经典的多线程协作方式,它可以让线程结果更加的均匀,假设只有两个线程的情况下,这种机制会线程一实现一次,线程二实现一次,轮流的执行。

案例实现:消费者生产者模式,生产者做出一份,那么消费者就消费一份,如果消费者没有消费完,那么生产者就需要等待,如果生产者没有生产一份,那么消费者就要等待。

代码:

生产者(Cooker)

package wait_notify;

public class Cooker extends Thread {
    @Override
    public void run() {
        while (true) {
            synchronized (Desk.object) {
                if(Desk.count==0){
                    break;
                }else {
                    if(Desk.foodlie==1){
                        try {
                            //生产者等待
                            Desk.object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        System.out.println(getName()+"要开始做饭了。。。");
                        Desk.foodlie=1;
                        //生产者唤醒消费者
                        Desk.object.notifyAll();
                    }
                }
            }
        }
    }
}

消费者: 

package wait_notify;

public class foodlie extends Thread {
    @Override
    public void run() {
        while (true){
            synchronized (Desk.object){
                if(Desk.count==0){
                    break;
                }
                else {
                    if (Desk.foodlie==0){
                        try {
                            //消费者等待
                            Desk.object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    else {
                        Desk.count--;
                        System.out.println(getName()+"开始吃饭"+"还剩下"+Desk.count+"碗");
                        //消费者唤醒生产者
                        Desk.object.notifyAll();
                        Desk.foodlie=0;

                    }
                }
            }
        }
    }
}

控制台:相当于桌子,判断是否有食物 

package wait_notify;

public class Desk {
    //定义消费者总共吃多少量
    public static int count =10;

    //定义锁对象
    public static Object object = new Object();

    //定义桌子上是否有食物 o:表示没有 1:表示有食物
    public static int foodlie = 0;
}

测试类:

package wait_notify;

public class Test {
    public static void main(String[] args) {
            foodlie foodlie = new foodlie();
        Cooker cooker =new Cooker();

        foodlie.setName("消费者");
        cooker.setName("厨师");

        foodlie.start();
        cooker.start();
    }
}

运行结果:

 

后续会持续的更新新的学习内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1134795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【蓝桥】小蓝的疑问

1、题目 问题描述 小蓝和小桥上完课后&#xff0c;小桥回顾了课上教的树形数据结构&#xff0c;他在地上画了一棵根节点为 1 的树&#xff0c;并且对每个节点都赋上了一个权值 w i w_i wi​。 小蓝对小桥多次询问&#xff0c;每次询问包含两个整数 x , k x,k x,k&#xff…

Iterator迭代器

一、基本概念 Iterator迭代器是一种接口&#xff0c;为不同的数据结构提供一种访问机制&#xff0c;即for … of 循环。当使用for…of循环遍历某种数据结构时&#xff0c;该循环会自动去寻找 Iterator 接口。任何数据结构只要部署Iterator接口&#xff0c;就可以完成遍历操作(…

基于Pytorch的驾驶员分心行为实时检测

本文使用深度学习和Pytorch(PyTorch 2.0.1\Torchvision 0.15.2)实时检测驾驶员的分心行为,并附录完整代码。 检测分心驾驶是现代汽车中最重要的功能之一。无论是自动驾驶汽车还是其它高端汽车,都配备了驾驶员监控系统,以持续跟踪驾驶员的行为。这对确保驾驶员保持目光在道路…

Unity的碰撞检测(二)

温馨提示&#xff1a;本文基于前一篇“Unity的碰撞检测(一)”继续探讨Collider输出&#xff0c;阅读本文则默认已阅读前文。 &#xff08;一&#xff09;测试说明 对于Collider输出&#xff0c;我们首先应该保证两个游戏对象具备的是碰撞器而非触发器&#xff0c;所以碰撞器的…

LSTM算法精解(附案例代码)

概念 LSTM&#xff08;Long Short-Term Memory&#xff09;是一种循环神经网络&#xff08;RNN&#xff09;的变种&#xff0c;用于处理序列数据&#xff0c;特别是在需要长期依赖关系的情况下。LSTM旨在解决传统RNN存在的梯度消失和梯度爆炸问题&#xff0c;这些问题使得RNN难…

18 Transformer 的动态流程

博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from333.1007.0.0 b 站直接看 配套 github 链接&#xff1a;https://github.com/nickchen121/Pre-training-language-model 配套博客链接&#xff1a;https://www.cnblogs.com/nickchen121/p/15105048.html 机…

【BI看板】superset api接口分析

superset 的图表功能已经非常强大了&#xff0c;但是要满足个性化需求&#xff0c;定制是比不可少的了。。。来吧&#xff0c;我们一起看看他的API。 自带api文档 URL 127.0.0.1:5000/swagger/v1 截图 是不是很熟悉&#xff0c;没错就是swagger了。 图表接口地址 127.0.0.1:…

2698 求一个整数的惩罚数 (子集和,DFS)

class Solution { public:bool dfs(int target, string s, int index, int sum) {// 只有整个字符串都被分割&#xff0c;求和&#xff0c;和看结果是不是等于targetif(index s.size()) {return sum target;}int num 0; // 在现在的子集中去依次加入余下的元素// 1 2 9 6// …

vue3 code format bug

vue code format bug vue客户端代码格式化缺陷&#xff0c;为了方便阅读和维护&#xff0c;对代码格式化发现这个缺陷 vue.global.min.3.2.26.js var Vuefunction(r){"use strict";function e(e,t){const nObject.create(null);var re.split(",");for(le…

VLAN实现二层流量隔离(mux-vlan)应用基础配置

MUX VLAN能够提供VLAN内的二层流量隔离机制。 MUX VLAN的类型如下所示 主VLAN: 加入主VLAN的接口可以和MUX VLAN内的所有接口进行通信 从VLAN: (1)隔离型从VLAN: 同一VLAN内接口之间不能互相通信&#xff0c;可以与主VLAN接口通信&#xff0c;不同从VLAN之间不能互相通信。 …

Xcode iOS app启用文件共享

在info.plist中添加如下两个配置 Supports opening documents in place Application supports iTunes file sharing 结果都为YES&#xff0c;如下图所示&#xff1a; 然后&#xff0c;iOS设备查看&#xff0c;文件->我的iPhone列表中有一个和你工程名相同的文件夹出现&…

MySQL——MySQL常见的面试知识

1、事务四大特性 原子性&#xff1a; 根据定义&#xff0c;原子性是指一个事务是一个不可分割的工作单位&#xff0c;其中的操作要么都做&#xff0c;要么都不做。即要么转账成功&#xff0c;要么转账失败&#xff0c;是不存在中间的状态&#xff01;MySQL的InnoDB引擎是靠 un…

Mysql数据库 4.SQL语言 DQL数据操纵语言 查询

DQL数据查询语言 从数据表中提取满足特定条件的记录 1.单表查询 2.多表查询 查询基础语法 select 关键字后指定要查询到的记录的哪些列 语法&#xff1a;select 列名&#xff08;字段名&#xff09;/某几列/全部列 from 表名 [具体条件]&#xff1b; select colnumName…

UI设计公司成长日记2:修身及持之以恒不断学习是要务

作者&#xff1a;蓝蓝设计 要做一个好的UI设计公司,不仅要在能力上设计能力一直&#xff08;十几年几十年&#xff09;保持优秀稳定的保持输出&#xff0c;以及心态的平和宽广。创始人对做公司要有信心&#xff0c;合伙人之间要同甘共苦&#xff0c;遵守规则&#xff0c;做好表…

text-indent 的特殊性

目录 前言 1. text-indent 的基本用法 代码示例 理解 2. text-indent 的特殊性质 2.1 负值 代码示例 理解 2.2 与其他文本属性的交互 代码示例 理解 2.3 在不同元素上的表现 代码示例 理解 3. 如何正确使用 text-indent 前言 text-indent 是 CSS 中一个用来控制…

1401 位置编码公式详细理解补充

博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https://github.com/nickchen121/Pre-training-language-model 配套博客链接:https://www.cnblogs.com/nickchen121/p/15105048.html Self-Attention:对于每…

day01:数据库DDL

一:基础概念 数据库:存储数据的仓库&#xff0c;数据是有组织的进行存储 数据库管理系统:操纵和管理数据库的大型软件 SQL&#xff1a;操作关系型数据库的编程语言&#xff0c;定义了一套操作关系型数据库统一标准 关系图 二:数据模型 关系型数据库:建…

LSM树原理详解

LSM树(Log-Structured-Merge-Tree)的名字往往会给初识者一个错误的印象&#xff0c;事实上&#xff0c;LSM树并不像B树、红黑树一样是一颗严格的树状数据结构&#xff0c;它其实是一种存储结构&#xff0c;目前HBase,LevelDB,RocksDB这些NoSQL存储都是采用的LSM树。 LSM树的核…

基于Java的智能仓库(进销存)管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

USB学习(2):USB端点和传输协议(数据包、事物)详解

接着上一篇文章USB学习(1)&#xff1a;USB基础之接口类型、协议标准、引脚分布、架构、时序和数据格式&#xff0c;继续介绍一下USB的相关知识。 文章目录 1 USB端点(Endpoints)1.1 基本知识1.2 四种端点 2 传输协议2.1 数据包类型2.1.1 令牌数据包(Token packets)2.1.2 数据数…