并发(八)–线程状态

一、你能说说进程与线程的区别吗?

1,两者的定义:

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

也就是,操作系统可以同时执行多个任务,每个任务就是进程
进程可以同时执行多个任务,每个任务就是线程。

2,进程与线程的区别:

  • 进程是资源分配最小单位,线程是程序执行的最小单位;
  • 进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,建立数据表来维护代码段、堆栈段和数据段,线程没有独立的地址空间,它使用相同的地址空间共享数据;
  • CPU切换一个线程比切换进程花费小;
  • 创建一个线程比进程开销小;
  • 线程占用的资源要⽐进程少很多。
  • 线程之间通信更方便,同一个进程下,线程共享全局变量,静态变量等数据,进程之间的通信需要以通信的方式(IPC)进行;(但多线程程序处理好同步与互斥是个难点)
  • 多进程程序更安全,生命力更强,一个进程死掉不会对另一个进程造成影响(源于有独立的地址空间),多线程程序更不易维护,一个线程死掉,整个进程就死掉了(因为共享地址空间);
  • 进程对资源保护要求高,开销大,效率相对较低,线程资源保护要求不高,但开销小,效率高,可频繁切换;

3,加强理解,做个简单的比喻:进程=火车,线程=车厢:

  • 线程在进程下行进(单纯的车厢无法运行)
  • 一个进程可以包含多个线程(一辆火车可以有多个车厢)
  • 不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
  • 同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
  • 进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
    -进程间不会相互影响 ,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
  • 进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)
  • 线程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。(比如火车上的洗手间)-“互斥锁”
  • 进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去)-“信号量”

以上这部分转载自:
https://mp.weixin.qq.com/s/i9y2OQsfVFTLXu0L6bALSg

二、线程的状态:

下面这个图是并发中的线程的状态:

线程在自身的生命周期中,并不是固定地处于某个状态,而是随着代码的执行在不同的状态之间进行切换。

在给定一个时刻,线程只能处于其中一个状态。

  • 新建( new ):新创建了一个线程对象。

  • 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象 的 start ()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取 cpu 的使用权 。

  • 运行( running ):可运行状态( runnable )的线程获得了 cpu 时间片( timeslice ) ,执行程序代码。

  • 阻塞( block ):阻塞状态是指线程因为某种原因放弃了 cpu 使用权,也即让出了 cpu timeslice ,暂时停止运行。直到线程进入可运行( runnable )状态,才有 机会再次获得 cpu timeslice 转到运行( running )状态。阻塞的情况分三种:

    • 等待阻塞运行( running )的线程执行 o.wait ()方法, JVM 会把该线程放 入等待队列( waitting
      queue )中。
    • 同步阻塞:运行( running )的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。
    • 其他阻塞: 运行( running )的线程执行 Thread . sleep ( long ms )或 t . join ()方法,或者发出了 I / O 请求时, JVM 会把该线程置为阻塞状态。当 sleep ()状态超时、 join ()等待线程终止或者超时、或者 I / O 处理完毕时,线程重新转入可运行( runnable )状态。
      -( 等待状态:当线程执行wait()方法之后,线程进入等待状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到**运行状态。**
  • 超时等待:就是在等待的基础上增加了超时限制,也就是超时时间到达时将会返回到**运行状态**。

  • 死亡( dead ):线程 run ()、 main () 方法执行结束,或者因异常退出了 run ()方法,则该线程结束生命周期。死亡的线程不可再次复生。)

阻塞状态:线程和其他线程抢锁没有抢到,就处于阻塞状态(此时线程还没进入同步代码块儿

等待状态:线程抢到了锁**进入了同步代码块**(由于某种业务需求)某些条件下Object.wait()了,就处于等待状态(此时线程已经进入了同步代码块儿)

start():启动线程,系统会把该run()方法当成线程执行体来处理
运行中的线程若调用它的sleep()或者yield()方法后才会放弃所占用的资源—也就是必须由该线程主动放弃所占用的资源

关于yeild()方法:调用yield()方法可以让运行状态的线程转入就绪状态(一般的都是从运行状态转到阻塞状态)

join():提供了让一个线程等待另一个线程完成的方法

–>当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的join线程执行完毕为止。

Java中线程中状态可分为五种:New(新建状态),Runnable(就绪状态),Running(运行状态),Blocked(阻塞状态),Dead(死亡状态)。

New:新建状态,当线程创建完成时为新建状态,即new Thread(…),还没有调用start方法时,线程处于新建状态。
Runnable:就绪状态,当调用线程的的start方法后,线程进入就绪状态,等待CPU资源。处于就绪状态的线程由Java运行时系统的线程调度程序(thread scheduler)来调度。
Running:运行状态,就绪状态的线程获取到CPU执行权以后进入运行状态,开始执行run方法。
Blocked:阻塞状态,线程没有执行完,由于某种原因(如,I/O操作等)让出CPU执行权,自身进入阻塞状态。
Dead:死亡状态,线程执行完成或者执行过程中出现异常,线程就会进入死亡状态。

这五种状态之间的转换关系如下图所示:

线程从阻塞状态只能进入就绪状态,无法直接进入运行状态。而就绪和运行状态之间的转换通常不受程序控制,而是由系统调度完成,当处于就绪状态的线程获得处理器资源时,该线程进入运行状态;当处于运行状态额线程失去处理器资源时,该线程进入就绪状态。但是 有一个方法例外:调用yield()方法可以让运行状态的线程转入就绪状态。

下面附上相应的链接:

https://mp.weixin.qq.com/s/K7G9JnuG3HEc2ECVBe52Ow

三、sleep和wait的区别:

1,wait可以指定时间也可以不指定时间,不指定时间的话,只能由对应的notify或notifyAll来唤醒

sleep:必须指定时间,时间到自动从冻结状态转换成运行时间(临时阻塞状态)

2,wait:线程会释放执行权,而且线程会释放锁
sleep:线程会释放执行权,但是不会释放锁

四、说说 如何停止一个正在运行的线程?

停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法

在java中有以下3种方法可以终止正在运行的线程

  • 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
  • 使用stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume一样都是过期作废的方法
  • 使用interrupt方法中断线程。

这里附上这个链接:(到时候认真看看):
https://mp.weixin.qq.com/s/t_NWl-cobHGUmbEzQo1SWQ(说说 如何停止一个正在运行的线程?)

下面这是转载自:
https://blog.csdn.net/qfc8930858/article/details/98473834

1、Java中API自带的stop()方法,来终止线程

Thread提供了一个stop()方法,但是stop()方法是一个被废弃的方法。为什么stop()方法被废弃而不被使用呢?原因是stop()方法太过于暴力,会强行把执行一半的线程终止。这样会就不会保证线程的资源正确释放,通常是没有给与线程完成资源释放工作的机会,因此会导致程序工作在不确定的状态下。

2、使用标志位 :使用boolean类型的变量,来终止线程:

那么如果需要停止一个线程时,应该怎么办?其实方法很简单,只是需要我们执行确定线程什么时候退出就可以了。仍用本例来说,只需要在ChangeObjectThread线程中增加一个stopMe()方法就可以了。

  static class CancelledTaggedRunnnable implements Runnable{private volatile boolean cancelled = false;@Overridepublic void run() {while(!cancelled){//没有停止需要做什么操作}//线程停止后需要干什么System.out.println("任务结束了");}public void cancell(){cancelled = true;}}

定义一个标志位:cancelled,cancelled为true是即run方法结束,反之继续while里面的任务。通过cancell方法来停止任务。

写一个测试类:

 @Testpublic void testCancelledTaggedRunnnable() throws InterruptedException {CancelledTaggedRunnnable taggedRunnnable = new CancelledTaggedRunnnable();Thread thread = new Thread(taggedRunnnable);thread.start();System.err.println(thread.isAlive());Thread.sleep(1000);taggedRunnnable.cancell();Thread.sleep(1000);System.err.println(thread.isAlive());Thread.sleep(1000);System.err.println(thread.isAlive());}

上述代码的操作为:启动该线程,1s秒调用cancell方法,从而来停止该线程。结果如下

3.使用interrupt方法中断线程:

中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其他线程进行了中断操作。中断好比其他线程对该线程打了个招呼,其他线程通过调用该线程的interrupt()方法对其进行中断操作。

线程通过检查自身是否被中断来进行响应,线程通过方法isInterrupted()来进行判断是否被中断,也可以调用静态方法Thread.interrupted()对当前线程的中断标识位进行复位。如果该线程已经处于终结状态,即使该线程被中断过,在调用该线程对象的isInterrupted()时依旧会返回false。

从Java的API中可以看到,许多声明抛出InterruptedException的方法(例如Thread.sleep(longmillis)方法,当线程在sleep()休眠时,如果被中断,这个异常就会产生)。这些方法在抛出InterruptedException之前,Java虚拟机会先将该线程的中断标识位清除,然后抛出InterruptedException,此时调用isInterrupted()方法将会返回false。

package com.baowei.threadinter;public class ThreadStopSafeInterrupted {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread() {@Overridepublic void run() {while (true) {// 使用中断机制,来终止线程if (Thread.currentThread().isInterrupted()) {System.out.println("Interrupted ...");break;}try {Thread.sleep(3000);} catch (InterruptedException e) {System.out.println("Interrupted When Sleep ...");// Thread.sleep()方法由于中断抛出异常。// Java虚拟机会先将该线程的中断标识位清除,然后抛出InterruptedException,// 因为在发生InterruptedException异常的时候,会清除中断标记// 如果不加处理,那么下一次循环开始的时候,就无法捕获这个异常。// 故在异常处理中,再次设置中断标记位Thread.currentThread().interrupt();}}}};// 开启线程thread.start();Thread.sleep(2000);thread.interrupt();}}

程序的运行结果:

Interrupted When Sleep ...
Interrupted ...

在沉睡中停止:

先sleep,后interrupt

  @Overridepublic void run() {super.run();try {System.out.println( "begin run" );Thread.sleep( 500 );System.out.println( "begin end" );} catch (InterruptedException e) {System.out.println("在沉睡中终止");e.printStackTrace();}}public static void main(String[] args) {try {MyThread5 thread5 = new MyThread5();thread5.start();Thread.sleep( 20 );thread5.interrupt();} catch (InterruptedException e) {System.out.println( "main catch" );e.printStackTrace();}}


从打印结果看,sleep状态下停止某一个线程,会进入catch语句,并清除状态值,变成false。

五、进程间通信的方式:

进程(注意这里是进程间)间通信的方式大概有以下几种:

共享内存:顾名思义,共享内存就是两个进程同时共享一块内存,然后在这块内存上的数据可以共同修改和读取,达到通信的目的;共享内存是最快的ipc方式;共享内存常与信号量进行配合使用,信号量是一个控制资源访问的标识符,简单来说就是一个计数器,通过信号量能实现锁以及著名的pv操作等,主要是用来实现进程间同步。

无名管道:无名管道是半双工的通信方式;并且只能在具有亲缘关系的进程之间使用(亲缘关系是指进程间的父子关系,兄弟关系等),具有亲缘关系的进程在创建时同时拥有一个无名管道的句柄,可以进行读写;无名管道不存在磁盘节点,只存在与内存中用完即销毁。

命名管道:命名管道也是半双工的通信方式;可以在不具有亲缘关系的进程间通信;有名管道存在磁盘节点,有对应的FIFO文件,凡是可以访问该路径的文件的进程均可以进行通信。

消息队列:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

套接字:套接字是网络编程的api,通过套接字可以不同的机器间的进程进行通信,常用于客户端进程和服务器进程的通信。

信号:信号是Unix系统中使用的最古老的进程间通信的方法之一。操作系统通过信号来通知进程系统中发生了某种预先规定好的事件(一组事件中的一个),它也是用户进程之间通信和同步的一种原始机制。一个键盘中断或者一个错误条件(比如进程试图访问它的虚拟内存中不存在的位置等)都有可能产生一个信号。Shell也使用信号向它的子进程发送作业控制信号。

转载自:
https://blog.csdn.net/qfc8930858/article/details/100165359

六、谈谈你对Java线程之间通信方式的理解:

注意这里是线程之间的通信方式:

通信方式

  • ①同步
  • ②while轮询的方式
  • ③wait/notify机制
  • ④管道通信

①同步:

这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信。

参考示例:

public class MyObject {synchronized public void methodA() {//do something....}synchronized public void methodB() {//do some other thing}
}public class ThreadA extends Thread {private MyObject object;
//省略构造方法@Overridepublic void run() {super.run();object.methodA();}
}public class ThreadB extends Thread {private MyObject object;
//省略构造方法@Overridepublic void run() {super.run();object.methodB();}
}public class Run {public static void main(String[] args) {MyObject object = new MyObject();//线程A与线程B 持有的是同一个对象:objectThreadA a = new ThreadA(object);ThreadB b = new ThreadB(object);a.start();b.start();}
}

由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的,比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了 通信。

这种方式,本质上就是“共享内存”式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。

②while轮询的方式:

代码如下:

import java.util.ArrayList;
import java.util.List;public class MyList {private List<String> list = new ArrayList<String>();public void add() {list.add("elements");}public int size() {return list.size();}
}import mylist.MyList;public class ThreadA extends Thread {private MyList list;public ThreadA(MyList list) {super();this.list = list;}@Overridepublic void run() {try {for (int i = 0; i < 10; i++) {list.add();System.out.println("添加了" + (i + 1) + "个元素");Thread.sleep(1000);}} catch (InterruptedException e) {e.printStackTrace();}}
}import mylist.MyList;public class ThreadB extends Thread {private MyList list;public ThreadB(MyList list) {super();this.list = list;}@Overridepublic void run() {try {while (true) {if (list.size() == 5) {System.out.println("==5, 线程b准备退出了");throw new InterruptedException();}}} catch (InterruptedException e) {e.printStackTrace();}}
}import mylist.MyList;
import extthread.ThreadA;
import extthread.ThreadB;public class Test {public static void main(String[] args) {MyList service = new MyList();ThreadA a = new ThreadA(service);a.setName("A");a.start();ThreadB b = new ThreadB(service);b.setName("B");b.start();}
}

在这种方式下,==线程A不断地改变条件,线程ThreadB不停地通过while语句检测这个条件(list.size()5)是否成立 ,从而实现了线程间的通信。但是这种方式会浪费CPU资源

之所以说它浪费资源,是因为JVM调度器将CPU交给线程B执行时,它没做啥“有用”的工作,只是在不断地测试 某个条件是否成立。就类似于现实生活中,某个人一直看着手机屏幕是否有电话来了,而不是:在干别的事情,当有电话来时,响铃通知TA电话来了。

③wait/notify机制:

代码如下:

import java.util.ArrayList;
import java.util.List;public class MyList {private static List<String> list = new ArrayList<String>();public static void add() {list.add("anyString");}public static int size() {return list.size();}
}public class ThreadA extends Thread {private Object lock;public ThreadA(Object lock) {super();this.lock = lock;}@Overridepublic void run() {try {synchronized (lock) {if (MyList.size() != 5) {System.out.println("wait begin "+ System.currentTimeMillis());lock.wait();System.out.println("wait end  "+ System.currentTimeMillis());}}} catch (InterruptedException e) {e.printStackTrace();}}
}public class ThreadB extends Thread {private Object lock;public ThreadB(Object lock) {super();this.lock = lock;}@Overridepublic void run() {try {synchronized (lock) {for (int i = 0; i < 10; i++) {MyList.add();if (MyList.size() == 5) {lock.notify();System.out.println("已经发出了通知");}System.out.println("添加了" + (i + 1) + "个元素!");Thread.sleep(1000);}}} catch (InterruptedException e) {e.printStackTrace();}}
}public class Run {public static void main(String[] args) {try {Object lock = new Object();ThreadA a = new ThreadA(lock);a.start();Thread.sleep(50);ThreadB b = new ThreadB(lock);b.start();} catch (InterruptedException e) {e.printStackTrace();}}
}

线程A要等待某个条件满足时(list.size()==5),才执行操作。线程B则向list中添加元素,改变list 的size。

A,B之间如何通信的呢?也就是说,线程A如何知道 list.size() 已经为5了呢?

这里用到了Object类的 wait() 和 notify() 方法

当条件未满足时(list.size() !=5),线程A调用wait() 放弃CPU,并进入阻塞状态。---不像②while轮询那样占用CPU

当条件满足时,线程B调用 notify()通知 线程A,所谓通知线程A,就是唤醒线程A,并让它进入可运行状态。

这种方式的一个好处就是CPU的利用率提高了。

但是也有一些缺点:比如,线程B先执行,一下子添加了5个元素并调用了notify()发送了通知,而此时线程A还执行;当线程A执行并调用wait()时,那它永远就不可能被唤醒了。因为,线程B已经发了通知了,以后不再发通知了。这说明:通知过早,会打乱程序的执行逻辑。

④管道通信:

就是使用java.io.PipedInputStream 和 java.io.PipedOutputStream进行通信

具体就不介绍了。分布式系统中说的两种通信机制:共享内存机制和消息通信机制。感觉前面的①中的synchronized关键字和②中的while轮询 “属于” 共享内存机制,由于是轮询的条件使用了volatile关键字修饰时,这就表示它们通过判断这个“共享的条件变量“是否改变了,来实现进程间的交流。

而管道通信,更像消息传递机制,也就是说:通过管道,将一个线程中的消息发送给另一个。

转载自:
https://mp.weixin.qq.com/s/0JXqTT3RzIHpVWMTzm3lnQ

并发(八)--线程状态相关推荐

  1. 【Java 并发编程】线程简介 ( 并发类型 | 线程状态 | CPU 数据缓存 )

    文章目录 一.并发类型 二.线程状态 三.CPU 数据缓存 一.并发类型 并发类型 : Thread Runnable Future ThreadPool 其中 Runnable , ThreadPo ...

  2. 如何查找历史线程阻塞原因_java并发编程-线程状态,线程阻塞方式,阻塞中的线程如何终止?...

    前面的例子通过volatile boolean来让任务终止,那么如果任务阻塞了? 如何终止它?本文来看下,参考think in java . 线程的状态 1.new:线程创建后的短暂状态,其分配系统资 ...

  3. 面试准备每日系列:计算机底层之并发编程(一)原子性、atomic、CAS、ABA、可见性、有序性、指令重排、volatile、内存屏障、缓存一致性、四核八线程

    文章目录 1. 什么是进程?什么是线程? 2. 线程切换 3. 四核八线程是什么意思 3.1 单核CPU设定多线程是否有意义 4. 并发编程的原子性 4.1 如何解决原子性问题 & atomi ...

  4. Java并发知识梳理(上):并发优缺点,线程状态转换,Java内存模型,Synchronized,Volatile,final,并发三特性,Lock与AQS,ReetrandLock

    努力的意义,就是,在以后的日子里,放眼望去全是自己喜欢的人和事! 整个系列文章为Java并发专题,一是自己的兴趣,二是,这部分在实际理解上很有难度,另外在面试过程中也是经常被问到.所以在学习过程中,记 ...

  5. 锁与并发工具包与线程池与LockSupport与Fork/Join框架与并行流串行流与阻塞队列与JPS,jstack命令查看死锁查看线程状态与AQS个人笔记九

    朝闻道,夕死可矣 本文共计 86564字,估计阅读时长1小时 点击进入->Thread源码万字逐行解析 文章目录 本文共计 86564字,估计阅读时长1小时 一锁 二Java中13个原子操作类 ...

  6. 【Java_多线程并发编程】基础篇—线程状态及实现多线程的两种方式

    1.Java多线程的概念 同一时间段内,位于同一处理器上多个已开启但未执行完毕的线程叫做多线程.他们通过轮寻获得CPU处理时间,从而在宏观上构成一种同时在执行的假象,实质上在任意时刻只有一个线程获得C ...

  7. 多线程、并发/并行、自定义线程类、线程安全、守护线程、定时器、线程状态、线程池

    目录 进程和线程: 进程: 线程: 多线程的好处: 线程调度: 分时调度: 抢占式调度: 并发与并行: 线程的生命周期: 实现线程的两种基本方式(还有第三种): 创建Thread线程类: 创建Runn ...

  8. java基础巩固-宇宙第一AiYWM:为了维持生计,多高(多线程与高并发)_Part1~整起(线程与进程篇:线程概念、线程状态、线程死锁)

    这个题目我感觉很多大哥大姐和我一样,虽然夹在众位大哥大姐中跟着一块喊着"多线程与高并发"的口号,但是这里面其实包含的东西并不像名字里面这么少.现在就开始咱们的旅程吧. 特此感谢,低 ...

  9. Java并发编程之线程状态总结

    线程状态 新创建(NEW):新创建了一个线程对象,但还没有调用start()方法,如new Thread(r). 可运行(RUNNABLE):调用start方法,线程处于runnable状态. 阻塞( ...

最新文章

  1. R语言可视化堆叠(stack)的条形图并通过另外一个分类变量分离(dodge)条形图(stacking by one variable and dodging by another)实战
  2. android init(system/core/init/init.c)分析
  3. 开发管理 (3) -项目启动会议
  4. 试用c51语言采样连续5次异常_学会这些自闭症儿童语言训练技巧,孩子开口说话不再困难...
  5. 存储世界瞬息万变 SSD掀行业浪潮
  6. Mac下关闭Sublime Text 3的更新检查
  7. Java main 方法详解
  8. oracle的in集合,oracle中in与not in集合中有空值问题
  9. MySQL5.5.15_linux下mysql-5.5.15安装详细步骤
  10. 前端算法-基本排序算法比较
  11. 【SAM】loj#6401. 字符串
  12. 计算机ascii码表
  13. 有关计算机计算类教案,计算教案
  14. SQL Server_SQL Server Windows NT - 64 bit
  15. WACV 2021 论文大盘点-GAN篇
  16. html剧场座位设计图,如何设计剧院座位,21个细部案例 | ArchDaily
  17. 2022-03-11 工作记录--PHP-eq(表示等于)、 neq(表示不等于)
  18. 深度学习 神经网络 神经元 单层神经网络的实现
  19. python qq群自动加入_Python实现向QQ群成员自动发邮件的方法
  20. kali linux安装mysql_kali linux 上安装MySQL 8.0.16

热门文章

  1. 知识付费加盟项目-小白也可以轻松上手
  2. java 布林线_java向量组——设计一个球,使它由一边(A点)运动到另一边(B点),运动到中间时,A点出现第二个球...
  3. mssql 计划怎每隔n秒_自闭症孩子各方面能力训练计划纲要
  4. Jsp+Servlet+tomcat实现简单的登录验证码案例
  5. python和台达plc通讯_项目实战:Qt西门子PLC通讯调试和模拟工具(包含PLC上位机通讯,PLC服务器)...
  6. kettle利用时间戳(timestamp)做增量抽取
  7. python qsub是啥意思_python – 使用qsub提交连续和独立作业的速度有多快?
  8. 安装sql数据库出现指定的驱动程序无效的问题
  9. Android逆向:某薇直播通过ClassLoader加载的jar包解密
  10. 计算机中常用的数制英语,计算机中常用的几种数制