了解多线程与并发

news2024/10/6 6:52:20

文章目录

  • 前言
  • 继承Thread类
  • 实现Runnable接口
  • 实现Callable和Future接口
  • 线程生命周期
  • 线程优先级
  • 线程加入操作
  • 线程休眠操作
  • 中断线程
  • 线程安全问题
  • 线程同步机制
    • 1. 同步代码块
    • 2. 同步方法
  • 线程暂停与恢复
  • 知识拓展
    • 死锁

前言

📋前言📋
💝博客:【无聊大侠hello word】💝
✍有一点思考,有一点想法,有一点理性!✍
✍本文由在下【无聊大侠hello word】原创,首发于CSDN✍

继承Thread类

使用Thread类创建并执行线程的具体步骤如下:

package cmo.basis.Demo;

/**
 * 描述:Thread使用介绍,继承Thread类
 *
 * 总结:
 * 使用Thread类创建并执行线程的具体步骤如下:
 * 1.创建Thread类的子类
 * 2.重写Thread类中run()方法
 * 3.创建Thread子类对象,即创建一个线程对象
 * 4.调用线程对象的start()方法启动线程,之后系统会自动调用重写的run()方法中的具体实现
 */
public class ThreadDemo extends Thread
{
    private Thread t;
    private String threadName;

    public ThreadDemo(String name)
    {
        this.threadName = name;
        System.out.println("创建线程,名称为:"+ threadName);
    }

    @Override
    public void run()
    {
        System.out.println("运行线程 "+ threadName);
        try
        {
            for (int i = 4; i > 0; i--)
            {
                System.out.println("线程名称为:"+ threadName + ","+ i);
                System.out.println("线程休息,时间为:100ms");
                Thread.sleep(100);
            }
        } catch (InterruptedException e)
        {
            System.out.println("线程 "+threadName+" 中断...");
        }
        System.out.println("线程 "+threadName+" 退出,终止...");
    }

    @Override
    public void start()
    {
        System.out.println("启动线程 "+threadName);
        // 避免NPE
        if(t == null)
        {
            t = new Thread(this, threadName);
            t.start();
            return;
        }
        this.start();
    }

    public static void main(String[] args)
    {
        ThreadDemo thread1 = new ThreadDemo("线程-1");
        thread1.start();

        ThreadDemo thread2 = new ThreadDemo("线程-2");
        thread2.start();
    }
}

实现Runnable接口

package cmo.basis.Demo;

/**
 * 描述:实现Runnable接口
 *
 * 总结:
 * 1.定义实现Runnable接口的类,实现run()方法
 * 2.创建Runnable对象并作为Thread类的target参数来创建Thread对象
 * 3.调用start()方法启动线程
 */
public class RunnableDemo implements Runnable
{
    private Thread t;
    private String threadName;

    public RunnableDemo(String name)
    {
        threadName = name;
        System.out.println("创建线程,名称为:"+ threadName);
    }

    @Override
    public void run()
    {
        System.out.println("运行线程 "+ threadName);
        try
        {
            for (int i = 4; i > 0; i--)
            {
                System.out.println("线程名称为:"+ threadName + ","+ i);
                System.out.println("线程休息,时间为:100ms");
                Thread.sleep(100);
            }
        } catch (InterruptedException e)
        {
            System.out.println("线程 "+threadName+" 中断...");
        }
        System.out.println("线程 "+threadName+" 退出,终止...");
    }

    public void start()
    {
        System.out.println("Starting "+threadName);
        // 避免NPE
        if(t == null)
        {
            t = new Thread(this, threadName);
            t.start();
            return;
        }
        this.start();
    }

    public static void main(String[] args)
    {
        RunnableDemo thread1 = new RunnableDemo("线程-1");
        thread1.start();

        RunnableDemo thread2 = new RunnableDemo("线程-2");
        thread2.start();
    }
}

实现Callable和Future接口

package cmo.basis.Demo;

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

/**
 * 描述:实现Callable接口
 *
 * 总结:
 * 1.声明实现Callable接口的类,实现call()方法,并定义反回值类型
 * 2.创建实现Callable类对象,使用FutureTask类包装Callable对象
 * 3.创建Thread对象,使用FutureTask对象作为Thread对象的target入参,并启动线程
 * 4.使用FutureTask对象的get()方法来获取线程结束后的反回值
 */
public class CallableDemo implements Callable<Integer>
{
    @Override
    public Integer call() throws Exception
    {
        int i = 0;
        for (; i < 5; i++)
        {
            System.out.println(Thread.currentThread().getName()+ " "+ i);
        }
        return i;
    }


    public static void main(String[] args)
    {
        CallableDemo demo = new CallableDemo();
        FutureTask<Integer> ft = new FutureTask<>(demo);
        for (int i = 0; i < 5; i++)
        {
            System.out.println(Thread.currentThread().getName()+ "的循环变量i的值:"+ i);
            if (i == 2)
            {
                new Thread(ft, "有返回值的线程").start();
            }
        }

        try
        {
            System.out.println("子线程的返回值:"+ ft.get());
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

线程生命周期

1.创建状态:

  • 线程被创建时(使用newThread创建线程对象),系统会分配资源并初始化该线程。这只是一个暂态,会一直保持到调用start()方法、线程进入运行或阻塞阶段之前

2.就绪状态:

  • 对一个创建状态的线程调用了start()方法后,线程进入就绪状态。就绪状态的线程会处于队列中等待JVM调度,直到线程获取资源。

3.运行状态:

  • 处于就绪状态的线程获取系统内存资源时,会执行run()方法,此时线程处于运行状态。处于运行状态的线程可以变成阻塞状态或死亡状态。

4.阻塞状态:

  • 如果一个线程执行了sleep()方法、suspend()方法或试图获取另一个已被其他线程占有的锁时,会暂时失去系统资源而进入阻塞状态。当设置的睡眠时间到期或获取系统资源后,线程可以重新进入就绪状态。

5.死亡:

  • 当线程执行完毕、发生异常或错误时,线程会终止并进入死亡阶段,这个阶段的线程是不可调度的,即不可再运行。
package cmo.basis.Demo;

/**
 * 描述:查看线程状态
 */
public class ThreadStateDemo implements Runnable
{
    public synchronized void notifying() throws InterruptedException
    {
        notify();
    }

    public synchronized void waiting() throws InterruptedException
    {
        wait();
    }

    @Override
    public void run()
    {
        try
        {
            System.out.println("当前线程休息100ms");
            Thread.sleep(100);
            waiting();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException 
    {
        ThreadStateDemo demo = new ThreadStateDemo();
        Thread thread = new Thread(demo);
        System.out.println("创建线程后状态为:"+ thread.getState());

        thread.start();
        System.out.println("启动线程后装填为:"+ thread.getState());

        Thread.sleep(50);
        System.out.println("主线程睡眠50ms后状态为:"+ thread.getState());

        Thread.sleep(100);
        System.out.println("wait后状态为:"+ thread.getState());

        demo.notifying();
        System.out.println("返回同步方法前状态为:"+ thread.getState());

        thread.join();
        System.out.println("结束线程后状态为:"+ thread.getState());
    }
}

线程优先级

JVM中的每一个线程都是存在优先级的,Java中的线程优先级是一个整数,取值为Thread.MIN_PRIORITY~Thread.MAX_PRIORITY,即1 ~ 10

package cmo.basis.Demo;

/**
 * 描述:线程优先级
 *
 * 总结:
 * JVM中的每一个线程都是存在优先级的,Java中的线程优先级是一个整数,取值为
 * Thread.MIN_PRIORITY~Thread.MAX_PRIORITY,即1~10
 */
public class ThreadPriority implements Runnable
{
    @Override
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println(Thread.currentThread().getName() + "输出:"+ i);
        }
    }

    public static void main(String[] args)
    {
        Thread maxPriority = new Thread(new ThreadPriority(), "高优先级线程");
        // 高优先级线程
        maxPriority.setPriority(Thread.MAX_PRIORITY);

        Thread minPriority = new Thread(new ThreadPriority(), "低优先级线程");
        // 低优先级线程
        minPriority.setPriority(Thread.MIN_PRIORITY);

        maxPriority.start();
        minPriority.start();
    }
}

线程加入操作

package cmo.basis.entity;

public class ThreadA extends Thread
{
    public ThreadA(String name)
    {
        super(name);
    }

    @Override
    public void run()
    {
        System.out.printf("%s线程开始\n", this.getName());
        for (int i = 0; i < 1000000; i++);
        System.out.printf("%s线程开始\n", this.getName());
    }
}

package cmo.basis.Demo;

import cmo.basis.entity.ThreadA;

/**
 * 描述:线程加入操作
 *
 * 总结:
 * 1.使用Thread类中的join()方法来加入线程
 * 2.如果需要在线程X执行前插入线程Y,这时可以使用线程X的join()方法加入线程Y,线程X会等待线程Y执行完成后再继续执行。
 */
public class JoinDemo
{
    public static void main(String[] args)
    {
        try
        {
            // 新建线程
            ThreadA t1 = new ThreadA("t-1");
            // 启动线程
            t1.start();
            // 将线程加入到主线程中,并且主线程会等待t1完成
            t1.join();

            System.out.printf("%s线程完成\n", Thread.currentThread().getState());
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

}

线程休眠操作

package cmo.basis.entity;

public class ThreadA extends Thread
{
    public ThreadA(String name)
    {
        super(name);
    }

    @Override
    public void run()
    {
        try {
            System.out.printf("%s线程开始\n", this.getName());
            for (int i = 0; i < 1000000; i++)
            {
                if (i == 10000)
                {
                    System.out.println("i循环到10000时线程休眠100毫秒");
                    this.sleep(100);
                }
            }
            System.out.printf("%s线程开始\n", this.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

package cmo.basis.Demo;

import cmo.basis.entity.ThreadA;

/** 
 * 描述:线程休眠操作
 * 
 * 总结:
 * sleep()方法设置的休眠时间到期后,线程并不会马上进入运行状态,而是进入就绪状态等待JVM调度。
 */
public class SleepDemo
{
    public static void main(String[] args)
    {
        try
        {
            // 新建线程
            ThreadA t1 = new ThreadA("t-1");
            // 启动线程
            t1.start();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

中断线程

package cmo.basis.entity;

public class ThreadA extends Thread
{
    private boolean isContiune = true;

    public ThreadA(String name)
    {
        super(name);
    }
    
    @Override
    public void run()
    {
        try {
            System.out.printf("%s线程开始\n", this.getName());
            for (int i = 0; i < 1000000; i++)
            {
                if (i == 10000)
                {
                    isContiune = false;
                    System.out.printf("%s中断线程\n", this.getName());
                    break;
                }
            }
            System.out.printf("%s线程开始\n", this.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

package cmo.basis.Demo;

import cmo.basis.entity.ThreadA;

/**
 * 描述:中断线程
 *
 * 总结:
 * Thread类中的stop()方法已被废弃,目前中断线程的方法是在run()方法中使用循环语句,
 * 通过条件语句进行判断,当满足条件跳出循环,使线程在执行完run()代码后自动中断
 */
public class StopDemo
{
    public static void main(String[] args)
    {
        try
        {
            // 新建线程
            ThreadA t1 = new ThreadA("t-1");
            // 启动线程
            t1.start();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

线程安全问题

1.在多线程程序运行时,会发生多个线程同时访问同一个对象或资源的情况下,第一、第二、第三线程对该对象进行修改,这就会导致该对象最终结果的不统一,引发线程安全问题

2.多个线程对count值进行修改,但是每次结果都不相同,造成了线程安全问题

package cmo.basis.Demo;

/**
 * 描述:线程安全问题
 *
 * 总结:
 * 1.在多线程程序运行时,会发生多个线程同时访问同一个对象或资源的情况下,
 * 第一、第二、第三线程对该对象进行修改,这就会导致该对象最终结果的不统一,引发线程安全问题
 * 2.多个线程对count值进行修改,但是每次结果都不相同,造成了线程安全问题
 */
public class ThreadSafe implements Runnable
{
    /**
     * 设置当前变量数量
     */
    private int count = 19;

    @Override
    public void run() 
    {
        for (int i = 0; i < 100; i++)
        {
            count++;
        }
        System.out.println(Thread.currentThread().getName()+ "线程当前count值为:"+ count);
    }

    public static void main(String[] args)
    {
        ThreadSafe threadSafe = new ThreadSafe();
        for (int i = 0; i < 5; i++)
        {
            new Thread(threadSafe).start();
        }
    }
}

线程同步机制

Java中提供了线程同步机制来解决线程安全问题,使用多个线程访问同一个资源时不发生冲突。Java中提供了 ”锁“ ,用来防止不同的线程在同一时间访问同一个对象或同一个代码块。

1. 同步代码块

Java中使用synchronized关键字来声明同步代码块,也就是所谓的 ”锁“ 它可以有效地防止多个线程同时访问同一个代码块而造成的冲突。

语法:

synchronized(Object)
{
	// 代码块
}
package cmo.basis.Demo;

/**
 * 描述:线程安全
 *
 * 总结:
 * 1.线程在进入synchronized代码块之前会先获取key对象的锁,直到key的锁被释放才会执行下一个线程,
 * 此时会避免key自增线程安全导致的key值重复的情况发生。
 * 2.在使用synchronized时,要尽量避免使用sleep()和yield()方法,因为被锁住的程序占用着对象锁,
 * 当程序休眠时,其他线程只能等待代码块被执行完后才能开始执行,这样会大大降低程序运行效率,同时锁一直占有着,
 * 系统内存这样也一直在无意地消耗
 */
public class ThreadSafe implements Runnable
{
    private Integer key = 0;

    @Override
    public void run()
    {
        synchronized (key)
        {
            key ++;
            System.out.println(Thread.currentThread().getName()+ ":" + key);
            try
            {
                Thread.sleep(100);
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        ThreadSafe threadSafe = new ThreadSafe();
        for (int i = 0; i < 10; i++)
        {
            new Thread(threadSafe, "线程-"+ i).start();
        }
    }
}

2. 同步方法

同步方法是指在方法前面使用synchronized 关键字修饰

语法:

synchronized void method()
{
	// 代码块
}
package cmo.basis.Demo;

/**
 * 描述:线程安全
 *
 * 总结:
 * 与synchronized同步代码块结果相同,不再描述
 */
public class ThreadSafe implements Runnable
{
    private Integer key = 0;

    public synchronized Integer getKey()
    {
        key ++;
        return key;
    }

    @Override
    public void run()
    {
        System.out.println(Thread.currentThread().getName()+ ":" + getKey());
        try
        {
            Thread.sleep(10);
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        ThreadSafe st = new ThreadSafe();
        for (int i = 0; i < 10; i++)
        {
            new Thread(st, "线程"+ i).start();
        }
    }
}

线程暂停与恢复

Java中Object类提供了wait()方法和notify()方法,wait()方法用来暂停线程,notify()方法则用来恢复线程。基本上所有类都拥有这两个方法。

package cmo.basis.Demo;

/**
 * 描述:线程暂停与恢复
 */
public class Demo
{
    public static void main(String[] args)
    {
        final Object obj = new Object();
        Thread t1 = new Thread()
        {
            @Override
            public void run()
            {
                synchronized (obj)
                {
                    System.out.println("线程1开始...");
                    try
                    {
                        System.out.println("线程1暂停...");
                        obj.wait();
                    } catch (InterruptedException e)
                    {
                        e.printStackTrace();
                    }
                    System.out.println("线程1结束...");
                }
            }
        };

        Thread t2 = new Thread()
        {
            @Override
            public void run()
            {
                synchronized (obj)
                {
                    System.out.println("线程2开始...");
                    System.out.println("线程1恢复...");
                    obj.notify();
                    System.out.println("线程2结束...");
                }
            }
        };

        // 启动线程
        t1.start();
        t2.start();
    }
}

知识拓展

死锁

一个对象可以使用synchronized方法或其他形式的加锁机制,让任务进入阻塞状态,此时会出现一种情况:一个任务在等待另一个任务,后者又在等待别的任务,不断循环下去,直到这条链路上的任务又在等待第一个任务释放锁。这时所有线程任务都无法继续执行,全都在等待任务解锁中不断循环下去,令程序进入死循环,也就是死锁。

package cmo.basis.Demo;

/**
 * 描述:死锁
 */
public class ThreadTest
{
    public static Object Lock1 = new Object();
    public static Object Lock2 = new Object();

    private static class ThreadA extends Thread
    {
        @Override
        public void run()
        {
            synchronized (Lock1)
            {
                System.out.println("线程1:持有Lock1对象锁...");

                try { Thread.sleep(10); }
                catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println("线程1:等待Lock2对象锁释放...");

                synchronized (Lock2)
                {
                    System.out.println("线程1:同时持有Lock1和Lock2的锁...");
                }
            }
        }
    }

    private static class ThreadB extends Thread
    {
        @Override
        public void run()
        {
            synchronized (Lock2)
            {
                System.out.println("线程2:持有Lock2对象锁...");

                try { Thread.sleep(10); }
                catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println("线程2:等待Lock1对象锁释放...");

                synchronized (Lock1)
                {
                    System.out.println("线程2:同时持有Lock1和Lock2的锁...");
                }
            }
        }
    }

    public static void main(String[] args)
    {
        ThreadA T1 = new ThreadA();
        ThreadB T2 = new ThreadB();
        T1.start();
        T2.start();
    }
}

在执行时会发生死锁,程序将永远挂起,两个线程都不能继续执行,一直在等待互相释放锁,其运行结果为:

在这里插入图片描述

总结:

死锁并不是一定只出现在两个线程间,多个线程之间也会出现互相等待的情况而发生死锁。出现死锁的几种条件如下所示:

  • 1 .互斥条件。任务使用的资源中至少有一个是不能共享的。
  • 2 .至少有一个任务必须持有一个资源且正在等待获取一个当前被别的任务持有资源。
  • 3 .资源不能被任务抢占,任务必须把资源释放当作普通事件。
  • 4 .必须有循环等待。

当这些条件满足时,就会发生死锁,因此解决死锁的方法就是破坏这四个条件中的任意一个

package cmo.basis.Demo;

/**
 * 描述:死锁
 */
public class ThreadTest
{
    public static Object Lock1 = new Object();
    public static Object Lock2 = new Object();

    private static class ThreadA extends Thread
    {
        @Override
        public void run()
        {
            synchronized (Lock1)
            {
                System.out.println("线程1:持有Lock1对象锁...");

                try { Thread.sleep(10); }
                catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println("线程1:等待Lock2对象锁释放...");

                synchronized (Lock2)
                {
                    System.out.println("线程1:同时持有Lock1和Lock2的锁...");
                }
            }
        }
    }

    private static class ThreadB extends Thread
    {
        @Override
        public void run()
        {
            synchronized (Lock1)
            {
                System.out.println("线程2:持有Lock2对象锁...");

                try { Thread.sleep(10); }
                catch (InterruptedException e) { e.printStackTrace(); }
                System.out.println("线程2:等待Lock1对象锁释放...");

                synchronized (Lock2)
                {
                    System.out.println("线程2:同时持有Lock1和Lock2的锁...");
                }
            }
        }
    }

    public static void main(String[] args)
    {
        ThreadA T1 = new ThreadA();
        ThreadB T2 = new ThreadB();
        T1.start();
        T2.start();
    }
}

在这里插入图片描述

先赞后看,养成习惯!!!^ _ ^ ❤️ ❤️ ❤️
码字不易,大家的支持就是我的坚持下去的动力。点赞后不要忘了关注我哦!

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

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

相关文章

用Devc++与easyx一步一步做游戏[启动界面部分]-之按钮制作

前面我们介绍了如何为dev c配置好easyx&#xff0c;至于用easyx能够做一些什么呢&#xff1f;大用处我不敢说&#xff0c;用来学习了解消息机制还是不错的。这我们来实现一个简单的游戏启动界面的设计&#xff0c;主要是按钮的设计。总体设计好的效果如下&#xff1a; GIF截图…

(免费分享)springboot音乐网站

开发工具&#xff1a;eclipse&#xff0c;数据库mysql5.7 jdk1.8技术&#xff1a;springbootmybatis/** * * * */package com.bjpowernode.music.ss.service.impl;import javax.annotation.Resource;import com.bjpowernode.music.common.AbstractService; import com.bjpowe…

基于 ROS 机器人和 RTAB-MAP 算法实现室内三维重建

本文叙如何利用RTAB-Map算法和Turtlebot3机器人在自己构建的室内场景中建图 文章目录1、安装依赖2、创建工作空间3、安装rtabmap和rtabmap_ros4、建立gazebo场景功能包5、建立机器人功能包6、为机器人添加kinect相机参考7、编译工作空间8、建立环境地图9、建图1、安装依赖 必要…

数据结构第五周 :(进制转换问题 + 迷宫自动行走问题 + 杨辉三角形 + 队列元素逆置 + 银行排队 + 整数划分问题 + 卡特兰数)

目录进制转换问题迷宫自动行走问题杨辉三角形队列元素逆置银行排队——队列整数划分问题买票问题——卡特兰数小兔的棋盘——卡特兰数进制转换问题 【问题描述】根据课堂讲授&#xff0c;请用“顺序栈”解决进制转换问题&#xff0c;不采用顺序栈&#xff0c;不给分。 【输入形…

前端屏幕录制工具 + 录制<video>标签内容

一、录制的实现思路 1.开始录制、停止录制、下载视频 2.Blob介绍 3.概念 var mediaRecord //用于录制视频 var mediaStream //视频流 var videoBuffer [] //保存的视频数据二、屏幕录制工具 下载地址&#xff1a; https://chrome.google.com/webstore/detail/tampermonkey…

Linux- 系统随你玩之--文本处理三剑客--grep继任者awk

文章目录1、sed概述1.1、 与vim等编辑器的区别&#xff1a;1.2、sed工作原理1.3 、sed数据处理原理1.4 、正则表达式概念2、 sed语法和常用选项2.1、语法&#xff1a;2.2、sed常用内部命令2.3、参数&#xff1a;3、 sed 正则表达式&#xff08;定位&#xff09;3.1 、数字定址…

管理机密(RH294)

在ansible中有一个命令行工具ansible-vault可用于创建 编辑 加密 解密 查看文件举个栗子ansible-vaultcreate filenameNew Vault password&#xff1a; #输入密码Confirm New Vault password&#xff1a; #确认密码也可以使用别的方法 比如创建一个密码文件ansible-vaultcreate…

互联网开发必读Git工具利器-《30天精通Git版本控管》中文版免费分享

本书介绍在软体开发领域&#xff0c;对原始码进行版本控管是非常重要的一件事&#xff0c;有别于Subversion或TFS这类集中式版本控管系统&#xff0c;Git是一套分散式版本控管系统&#xff0c;并带来许多版本控管上的各种优势与解决传统集中式版本控管的缺失&#xff0c;例如支…

Spring Cloud_Hystrix断路器

目录一、概述1.分布式系统面临的问题2.是什么3.能干嘛4.官网资料5.Hystrix官宣&#xff0c;停更进维二、Hystrix重要概念1.服务降级Fallback2.服务熔断Breaker3.服务限流Flowlimit三、hystrix案例1.构建2.高并发测试3.故障现象和导致原因4.上诉结论5.如何解决&#xff1f;解决的…

面试_Selenium常见问题

1.selenium 工作原理 1.对于每一条Selenium脚本&#xff0c;一个http请求会被创建并且发送给浏览器的驱动 2.浏览器驱动中包含了一个HTTP Server&#xff0c;用来接收这些http请求 3.HTTP Server接收到请求后根据请求来具体操控对应的浏览器 4.浏览器执行具体的测试步骤 5.浏览…

Smali语法小记

Smali语法小记 介绍 在执行 Android Java 层的代码时&#xff0c;其实就是 Dalvik(ART) 虚拟机&#xff08;使用 C 或 C 代码实现&#xff09;在解析 Dalvik 字节码&#xff0c;从而模拟程序的执行过程。 自然&#xff0c;Dalvik 字节码晦涩难懂&#xff0c;研究人员们给出了…

通过 eShopOnContainers 项目学习一下微服务

这里是项目地址 https://github.com/dotnet-architecture/eShopOnContainers, 这是微软创建的一个基于 .NET 平台的微服务架构的示例应用程序&#xff0c;里面基本上市面上主流的时髦的技术都用上了。 因为涉及的内容比较多&#xff0c;所以我们只简单查看一下微服务的代码实现…

信息抽取命名实体识别和关系抽取)

信息抽取的定义为&#xff1a;从自然语言文本中抽取指定类型的实体&#xff0c;关系、事件等事实信息。并形成结构化数据输出的文本处理技术。 信息抽取是从文本数据中抽取特定信息的一种技术&#xff0c;文本数据由医学具体的单位构成&#xff0c;例如&#xff0c;句子、段落、…

JavaWeb—Vue的简单介绍

1 Vue介绍 概述 Vue是一套构建用户界面的渐进式前端框架。只关注视图层&#xff0c;并且非常容易学习&#xff0c;还可以很方便的与其它库或已有项目整合。通过尽可能简单的API来实现响应数据的绑定和组合的视图组件。 数据渲染 数据库 --JDBC–> java程序 --http协议–>…

《MySQL实战45讲》——学习笔记23 “binlogredolog 的写入机制/组提交机制“

本篇主要介绍数据的可靠性有关的知识&#xff0c;包括binlog的写入机制和redolog的写入机制&#xff0c;通过了解这些机制从而可以在MySQL的IO性能瓶颈上做些优化&#xff1b;前文介绍了MySQL在可靠性、性能相关的概念&#xff0c;包括WAL技术、redolog与binlog、2阶段提交、ch…

阿里云图标使用 (symbol 引用方式)

阿里云图标网址: https://www.iconfont.cn/ 一、登录注册 这个简单&#xff0c;就不说了 二、给当前项目找图库 2.1、添加项目 2.2、寻找图标添加入库 添加入库 2.3、打开入库 的图标添加到指定项目 添加到当前项目 1 2 三、项目使用图标 ( symbol 引用方式) 3.1、下…

《HelloGitHub》第 82 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01;简介HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。https://github.com/521xueweihan/HelloGitHub这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Pyth…

Studio One6有哪些新功能及系统配置要求介绍

Studio One6全新版本上线记录、生产、混合、掌握和执行所有操作。从工作室到舞台&#xff0c;Studio One6以易用为核心&#xff0c;是您的创意合作伙伴。当你准备好登上舞台时&#xff0c;Studio One就在那里。只有Studio One从最初的灵感到完整的制作&#xff0c;最终混音到精…

一个数码管显示0-F

数码管的一种是半导体发光器件&#xff0c;数码管可分为七段数码管和八段数码管&#xff0c;区别在于八段数码管比七段数码管多一个用于显示小数点的发光二极管单元DP&#xff08;decimal point&#xff09;&#xff0c;其基本单元是发光二极管。七段数码管是一类价格便宜使用简…

VuePress 搭建结合GitHub Pages CI

简介 VuePress 是尤雨溪&#xff08;vue.js 框架作者&#xff09;4月12日发布的一个全新的基于 vue 的静态网站生成器&#xff0c;实际上就是一个 vue 的 spa 应用&#xff0c;内置 webpack&#xff0c;可以用来写文档。详见 VuePress中文网 其实类似的建站工具有很多&#x…