当前位置:首页 > 科技  > 软件

老后端被借调去写Java了,含泪总结的Java多线程编程基础

来源: 责编: 时间:2023-12-21 17:10:49 131观看
导读这篇文章咱们总结一下 Java线程的基础,打好基础,后面几篇再学多线程的同步控制中的各种锁、线程通信等方面的知识时就会觉得更容易些。本文的大纲如下:线程在计算机系统里每个进程(Process)都代表着一个运行着的程序,比如打

这篇文章咱们总结一下 Java线程的基础,打好基础,后面几篇再学多线程的同步控制中的各种锁、线程通信等方面的知识时就会觉得更容易些。jto28资讯网——每日最新资讯28at.com

本文的大纲如下:jto28资讯网——每日最新资讯28at.com

jto28资讯网——每日最新资讯28at.com

jto28资讯网——每日最新资讯28at.com

线程

在计算机系统里每个进程(Process)都代表着一个运行着的程序,比如打开微信,系统就会为微信开一个进程--进程是对运行时程序的封装,是系统进行资源调度和分配的基本单位。jto28资讯网——每日最新资讯28at.com

一个进程下可以有很多个线程,还拿微信举例子,我们用微信的时候除了给好友收发消息,还可以在里面看公众号,看公众号的时候,也不影响我们的微信收到其他人发给我们的消息,这就以为着运行的微信的进程,还开启了多个线程来同时完成这些子任务。jto28资讯网——每日最新资讯28at.com

线程是进程的子任务,是CPU调度和分派的基本单位,用于保证程序的实时性,实现进程内部的并发,线程同时也是操作系统可识别的最小执行和调度单位。jto28资讯网——每日最新资讯28at.com

在 Java 里线程是程序执行的载体,我们写的代码就是由线程运行的。有的时候为了增加程序的执行效率,我们不得不使用多线程进行编程,虽然多线程能最大化程序利用 CPU 的效率,但是程序用多写成进行任务处理,也是BUG的高发地,主要原因还是多线程环境下有些问题一旦被疏忽就会造成执行结果不符合预期的BUG。jto28资讯网——每日最新资讯28at.com

平时我们写代码思考问题时的习惯思维是单线程的,写多线程的时候得刻意切换一下才行,这就要求我们要了解清楚线程在不同运行条件下所表现出来的行为才行。jto28资讯网——每日最新资讯28at.com

首先我们来看一下在 Java 中是怎么表示线程的。jto28资讯网——每日最新资讯28at.com

Java 中的线程

到目前为止,我们写的所有 Java 程序代码都是在由JVM给创建的主线程(Main Thread) 中执行的。Java 线程就像一个虚拟 CPU,可以在运行的 Java 应用程序中执行 Java 代码。当一个 Java 应用程序启动时,它的入口方法 main() 方法由主线程执行。主线程(Main Thread)是一个由 Java 虚拟机创建的运行应用程序的特殊线程。jto28资讯网——每日最新资讯28at.com

我们在 Java 里万物皆对象,所以系统的线程在 Java 里也是用对象表示的,线程是类 java.lang.Thread 类或者其子类的实例。在 Java 应用程序内部, 我们可以通过线程对象创建和启动更多线程,这些线程可以与主线程并行执行应用程序的代码。jto28资讯网——每日最新资讯28at.com

下面看一下怎么在 Java 程序里创建和启动线程。jto28资讯网——每日最新资讯28at.com

创建和启动线程

在 Java 中创建一个线程,就是创建一个Thread类的实例jto28资讯网——每日最新资讯28at.com

 Thread thread = new Thread();

启动线程就是调用Thread对象的start()方法jto28资讯网——每日最新资讯28at.com

  thread.start();

当然,这个例子没有指定线程要执行的代码,所以线程将在启动后立即停止。 让线程执行逻辑,需要给线程对象指定执行体。jto28资讯网——每日最新资讯28at.com

指定线程要执行的代码

有两种方法可以给线程指定要执行的代码。jto28资讯网——每日最新资讯28at.com

  • 第一种是,创建Thread类的子类,在子类中覆盖Thread类的run() 方法,在这个run() 方法的方法体里的代码,就是指定给线程去执行的代码。
  • 第二种是,将实现 Runnable (java.lang.Runnable) 的对象传递给Thread构造方法,创建Thread实例。

其实,还有第三种给线程指定执行代码的方法,不过细究下来算是第二种方法的特殊使用方式,下面我们看看这三种指定线程执行方法体的方式,以及它们之间的区别。jto28资讯网——每日最新资讯28at.com

1.通过 Thread 子类指定要执行的代码

通过继承Thread类创建线程的步骤:jto28资讯网——每日最新资讯28at.com

(1) 定义 Thread 类的子类,并覆盖该类的 run() 方法。run() 方法的方法体就代表了线程要完成的任务,因此把 run() 方法称为执行体。jto28资讯网——每日最新资讯28at.com

(2) 创建 Thread 子类的实例,即创建了线程对象。jto28资讯网——每日最新资讯28at.com

(3) 调用线程对象的 start() 方法来启动该线程。jto28资讯网——每日最新资讯28at.com

package com.learnthread;public class ThreadFirstRunDemo {    public static void main(String[] args) {        // 实例化线程对象        MyThread threadA = new MyFirstThread("线程-A");        MyThread threadB = new MyFirstThread("线程-B");        // 启动线程        threadA.start();        threadB.start();    }    static class MyFirstThread extends Thread {        private int ticket = 5;        MyThread(String name) {            super(name);        }        @Override        public void run() {            while (ticket > 0) {                System.out.println(Thread.currentThread().getName() + " 卖出了第 " + ticket + " 张票");                ticket--;            }        }    }}

上面的程序,主线程启动调用A、B两个线程的start() 后,并没有通过调用wait() 等待他们执行结束。A、B两个线程的执行体,会并发地被系统执行,等线程都直接结束后,程序才会退出。jto28资讯网——每日最新资讯28at.com

2.通过实现 Runnable 接口指定要执行的代码

Runnable 接口的定义如下,只有一个 run() 方法的定义:jto28资讯网——每日最新资讯28at.com

package java.lang;public interface Runnable {    public abstract void run();}

其实,Thread 类实现的也是 Runnable 接口。 在 Thread 类的重载构造方法里,支持接收一个实现了 Runnale 接口的对象作为其 target 参数来初始化线程对象。jto28资讯网——每日最新资讯28at.com

public class Thread implements Runnable {        ... public Thread(Runnable target) {        init(null, target, "Thread-" + nextThreadNum(), 0);    }        ...    public Thread(Runnable target, String name) {        init(null, target, name, 0);    }    ...}

通过实现 Runnable 接口创建线程的步骤如下:jto28资讯网——每日最新资讯28at.com

(1) 定义 Runnable 接口的实现,实现该接口的 run 方法。该 run 方法的方法体同样是线程的执行体。jto28资讯网——每日最新资讯28at.com

(2) 创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 参数来创建 Thread 对象,该 Thread 对象才是真正的线程对象。jto28资讯网——每日最新资讯28at.com

(3) 调用线程对象的 start 方法来启动线程并执行。jto28资讯网——每日最新资讯28at.com

package com.learnthread;public class RunnableThreadDemo {    public static void main(String[] args) {        // 实例化线程对象        Thread threadA = new Thread(new MyThread(), "Runnable 线程-A");        Thread threadB = new Thread(new MyThread(), "Runnable 线程-B");        // 启动线程        threadA.start();        threadB.start();    }    static class MyThread implements Runnable {        private int ticket = 5;        @Override        public void run() {            while (ticket > 0) {                System.out.println(Thread.currentThread().getName() + " 卖出了第 " + ticket + " 张票");                ticket--;            }        }    }}

运行上面例程会有以下输出,同样程序会在所以线程执行完后退出。jto28资讯网——每日最新资讯28at.com

Runnable 线程-B 卖出了第 5 张票Runnable 线程-B 卖出了第 4 张票Runnable 线程-B 卖出了第 3 张票Runnable 线程-B 卖出了第 2 张票Runnable 线程-B 卖出了第 1 张票Runnable 线程-A 卖出了第 5 张票Runnable 线程-A 卖出了第 4 张票Runnable 线程-A 卖出了第 3 张票Runnable 线程-A 卖出了第 2 张票Runnable 线程-A 卖出了第 1 张票Process finished with exit code 0

既然是给 Thread 传递 Runnable 接口的实现对象即可,那么除了普通的定义类实现接口的方式,我们还可以使用匿名类和 Lambda 表达式的方式来定义 Runnable 的实现。jto28资讯网——每日最新资讯28at.com

  • 使用 Runnable 的匿名类作为参数创建 Thread 对象:
Thread threadA = new Thread(new Runnable() {    private int ticket = 5;    @Override    public void run() {        while (ticket > 0) {            System.out.println(Thread.currentThread().getName() + " 卖出了第 " + ticket + " 张票");            ticket--;        }    }}, "Runnable 线程-A");
  • 使用实现了 Runnable 的 Lambda 表达式作为参数创建 Thread 对象:
Runnable runnable = () -> { System.out.println("Lambda Runnable running"); };Thread threadB = new Thread(runnable, "Runnable 线程-B");

因为,Lambda 是无状态的,定义不了内部属性,这里就举个简单的打印一行输出的例子了,理解一下这种用法即可。jto28资讯网——每日最新资讯28at.com

jto28资讯网——每日最新资讯28at.com

3.获取线程的执行结果

上面两种方法虽然能指定线程执行体里要执行的任务,但是都没有返回值,如果想让线程的执行体方法有返回值,且能被外部创建它的父线程获取到返回值,就需要结合J.U.C 里提供的 Callable、Future 接口来实现线程的执行体方法才行。jto28资讯网——每日最新资讯28at.com

J.U.C 是 java.util.concurrent 包的缩写,提供了很多并发编程的工具类,后面会详细学习。jto28资讯网——每日最新资讯28at.com

jto28资讯网——每日最新资讯28at.com

Callable 接口只声明了一个方法,这个方法叫做 call():jto28资讯网——每日最新资讯28at.com

package java.util.concurrent;public interface Callable<V> {    V call() throws Exception;}

Future 就是对于具体的 Callable 任务的执行进行取消、查询是否完成、获取执行结果的。可以通过 get 方法获取 Callable 的 call 方法的执行结果,但是要注意该方法会阻塞直到任务返回结果。jto28资讯网——每日最新资讯28at.com

public interface Future<V> {    boolean cancel(boolean mayInterruptIfRunning);    boolean isCancelled();    boolean isDone();    V get() throws InterruptedException, ExecutionException;    V get(long timeout, TimeUnit unit)        throws InterruptedException, ExecutionException, TimeoutException;}

Java 的 J.U.C 里给出了 Future 接口的一个实现 FutureTask,它同时实现了 Future 和 Runnable 接口,所以,FutureTask 既可以作为 Runnable 被线程执行,又可以作为 Future 得到 Callable 的返回值。jto28资讯网——每日最新资讯28at.com

下面是一个 Callable 实现类和 FutureTask 结合使用让主线程获取子线程执行结果的一个简单的示例:jto28资讯网——每日最新资讯28at.com

package com.learnthread;import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;public class CallableDemo implements Callable<Integer> {    @Override    public Integer call() {        int i = 0;        for (i = 0; i < 20; i++) {            if (i == 5) {                break;            }            System.out.println(Thread.currentThread().getName() + " " + i);        }        return i;    }    public static void main(String[] args) {        CallableDemo tt = new CallableDemo();        FutureTask<Integer> ft = new FutureTask<>(tt);        Thread t = new Thread(ft);        t.start();        try {            System.out.println(Thread.currentThread().getName() + " " + ft.get());        } catch (Exception e) {            e.printStackTrace();        }    }}

上面我们把 FutureTask 作为 Thread 构造方法的 Runnable 类型参数 target 的实参,在它的基础上创建线程, 执行逻辑。所以本质上 Callable + FutureTask 这种方式也是第二种通过实现 Runnable 接口给线程指定执行体的,只不过是由 FutureTask 包装了一层,由它的 run 方法再去调用 Callable 的 call 方法。例程运行后的输出如下:jto28资讯网——每日最新资讯28at.com

Thread-0 0Thread-0 1Thread-0 2Thread-0 3Thread-0 4main 5

Callable 更常用的方式是结合线程池来使用,在线程池接口 ExecutorService 中定义了多个可接收 Callable 作为线程执行任务的方法 submit、invokeAny、invokeAll 等,这个等学到线程池了我们再去学习。jto28资讯网——每日最新资讯28at.com

jto28资讯网——每日最新资讯28at.com

Java 线程的使用陷阱

在刚开始接触和学习 Java 线程相关的知识时,一个常见的错误是,在创建线程的线程里,调用 Thread 对象的 run() 方法而不是调用 start() 方法。jto28资讯网——每日最新资讯28at.com

Runnable myRunnable = new Runnable() {    @Override    public void run() {  System.out.println("Anonymous Runnable running");    }};Thread newThread = new Thread(myRunnable);newThread.run();  // 应该调用 newThread.start();

起初你可能没有注意到这么干有啥错,因为 Runnable 的 run() 方法正常地被执行,输出了我们想要的结果。jto28资讯网——每日最新资讯28at.com

但是,这么做 run() 不会由我们刚刚创建的新线程执行,而是由创建 newThread 对象的线程执行的 。要让新创建的线程--newThread 调用 myRunnable 实例的 run() 方法,必须调用 newThread.start() 方法才行。jto28资讯网——每日最新资讯28at.com

线程对象的基本用法

11.线程对象常用的方法

Thread 线程常用的方法有以下这些:jto28资讯网——每日最新资讯28at.com

方法
jto28资讯网——每日最新资讯28at.com

描述
jto28资讯网——每日最新资讯28at.com

runjto28资讯网——每日最新资讯28at.com

线程的执行实体,不需要我们主动调用,调用线程的start() 就会执行run() 方法里的执行体
jto28资讯网——每日最新资讯28at.com

start
jto28资讯网——每日最新资讯28at.com

线程的启动方法。
jto28资讯网——每日最新资讯28at.com

Thread.currentThread
jto28资讯网——每日最新资讯28at.com

Thread 类提供的静态方法,返回对当前正在执行的线程对象的引用。
jto28资讯网——每日最新资讯28at.com

setName
jto28资讯网——每日最新资讯28at.com

设置线程名称。
jto28资讯网——每日最新资讯28at.com

getName
jto28资讯网——每日最新资讯28at.com

获取线程名称。
jto28资讯网——每日最新资讯28at.com

setPriority
jto28资讯网——每日最新资讯28at.com

设置线程优先级。Java 中的线程优先级的范围是 [1,10],一般来说,高优先级的线程在运行时会具有优先权。可以通过 thread.setPriority(Thread.MAX_PRIORITY) 的方式设置,默认优先级为 5。
jto28资讯网——每日最新资讯28at.com

getPriority
jto28资讯网——每日最新资讯28at.com

获取线程优先级。
jto28资讯网——每日最新资讯28at.com

setDaemon
jto28资讯网——每日最新资讯28at.com

设置线程为守护线程。
jto28资讯网——每日最新资讯28at.com

isDaemon
jto28资讯网——每日最新资讯28at.com

判断线程是否为守护线程。
jto28资讯网——每日最新资讯28at.com

isAlive
jto28资讯网——每日最新资讯28at.com

判断线程是否启动。
jto28资讯网——每日最新资讯28at.com

interrupt
jto28资讯网——每日最新资讯28at.com

中断线程的运行。
jto28资讯网——每日最新资讯28at.com

Thread.interrupted
jto28资讯网——每日最新资讯28at.com

测试当前线程是否已被中断。
jto28资讯网——每日最新资讯28at.com

join
jto28资讯网——每日最新资讯28at.com

可以使一个线程强制运行,线程强制运行期间,其他线程无法运行,必须等待此线程完成之后才可以继续执行。
jto28资讯网——每日最新资讯28at.com

Thread.sleep
jto28资讯网——每日最新资讯28at.com

静态方法。将当前正在执行的线程休眠。
jto28资讯网——每日最新资讯28at.com

Thread.yield
jto28资讯网——每日最新资讯28at.com

静态方法。将当前正在执行的线程暂停,让出CPU,让其他线程执行。
jto28资讯网——每日最新资讯28at.com

2.线程休眠

使用 Thread.sleep 方法可以使得当前正在执行的线程进入休眠状态。 使用 Thread.sleep 需要向其传入一个整数值,这个值表示线程将要休眠的毫秒数。 Thread.sleep 方法可能会抛出 InterruptedException,因为异常不能跨线程传播回主线程中,因此必须在本地进行处理。线程中抛出的其它异常也同样需要在本地进行处理。jto28资讯网——每日最新资讯28at.com

public class ThreadSleepDemo {    public static void main(String[] args) {        new Thread(new MyThread("线程A", 500)).start();        new Thread(new MyThread("线程B", 1000)).start();        new Thread(new MyThread("线程C", 1500)).start();    }    static class MyThread implements Runnable {        /** 线程名称 */        private String name;        /** 休眠时间 */        private int time;        private MyThread(String name, int time) {            this.name = name;            this.time = time;        }        @Override        public void run() {            try {                // 休眠指定的时间                Thread.sleep(this.time);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(this.name + "休眠" + this.time + "毫秒。");        }    }}

上面例程开启了3个线程,在各自的线程执行体里让各自线程休眠了 500、1000 和 1500 ms ,线程 C 休眠结束后,整个程序退出。jto28资讯网——每日最新资讯28at.com

线程A休眠500毫秒。线程B休眠1000毫秒。线程C休眠1500毫秒。Process finished with exit code 0

3.终止线程

当一个线程运行时,另一个线程可以直接通过 interrupt 方法中断其运行状态。jto28资讯网——每日最新资讯28at.com

public class ThreadInterruptDemo {    public static void main(String[] args) {        MyThread mt = new MyThread(); // 实例化Runnable实现类的对象        Thread t = new Thread(mt, "线程"); // 实例化Thread对象        t.start(); // 启动线程        try {            Thread.sleep(2000); // 主线程休眠2秒        } catch (InterruptedException e) {            System.out.println("主线程休眠被终止");        }        t.interrupt(); // 中断 mt 线程的执行    }    static class MyThread implements Runnable {        @Override        public void run() {            System.out.println("1、进入run()方法");            try {                Thread.sleep(10000); // 线程休眠10秒                System.out.println("2、已经完成了休眠");            } catch (InterruptedException e) {                System.out.println("3、MyThread线程休眠被终止");                return; // 返回调用处            }            System.out.println("4、run()方法正常结束");        }    }}

如果一个线程的 run 方法执行一个无限循环,并且没有执行 sleep 等会抛出 InterruptedException 的操作,那么调用线程的 interrupt 方法就无法使线程提前结束。jto28资讯网——每日最新资讯28at.com

不过调用 interrupt 方法会设置线程的中断标记,此时被设置中断标记的线程再调用 interrupted 方法会返回 true。因此可以在线程的执行体循环体中使用 interrupted 方法来判断当前线程是否处于中断状态,从而提前结束线程。jto28资讯网——每日最新资讯28at.com

看下面这个,可以有效终止线程执行的示例:jto28资讯网——每日最新资讯28at.com

package com.learnthread;import java.util.concurrent.TimeUnit;public class ThreadInterruptEffectivelyDemo {    public static void main(String[] args) throws Exception {        MyTask task = new MyTask();        Thread thread = new Thread(task, "线程-A");        thread.start();        TimeUnit.MILLISECONDS.sleep(50);        thread.interrupt();    }    private static class MyTask implements Runnable {        private volatile long count = 0L;        @Override        public void run() {            System.out.println(Thread.currentThread().getName() + " 线程启动");            // 通过 Thread.interrupted 和 interrupt 配合来控制线程终止            while (!Thread.interrupted()) {                System.out.println(count++);            }            System.out.println(Thread.currentThread().getName() + " 线程终止");        }    }}

主线程在启动线程-A后,主动休眠50毫秒,线程-A的执行体里会不断打印计数器的值,等休眠结束后主线程通过调用线程-A的 interrupt 方法设置了线程的中断标记,这时线程-A的执行体中通过 Thread.interrupted() 就能判断出线程被设置了中断状态,随后结束执行退出。jto28资讯网——每日最新资讯28at.com

4.守护线程

(1) 什么是守护线程?jto28资讯网——每日最新资讯28at.com

  • 守护线程(Daemon Thread)是在后台执行并且不会阻止 JVM 终止的线程。当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程。
  • 与守护线程(Daemon Thread)相反的,叫用户线程(User Thread),也就是非守护线程。

(2) 为什么需要守护线程?jto28资讯网——每日最新资讯28at.com

守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。典型的应用就是垃圾回收器。jto28资讯网——每日最新资讯28at.com

(3) 如何使用守护线程?jto28资讯网——每日最新资讯28at.com

可以使用 isDaemon 方法判断线程是否为守护线程。jto28资讯网——每日最新资讯28at.com

可以使用 setDaemon 方法设置线程为守护线程。jto28资讯网——每日最新资讯28at.com

  • 正在运行的用户线程无法设置为守护线程,所以 setDaemon 必须在 thread.start 方法之前设置,否则会抛出 llegalThreadStateException 异常;
  • 一个守护线程创建的子线程依然是守护线程。
  • 不要认为所有的应用都可以分配给守护线程来进行服务,比如读写操作或者计算逻辑就不能。
public class ThreadDaemonDemo {    public static void main(String[] args) {        Thread t = new Thread(new MyThread(), "线程");        t.setDaemon(true); // 此线程在后台运行        System.out.println("线程 t 是否是守护进程:" + t.isDaemon());        t.start(); // 启动线程    }    static class MyThread implements Runnable {        @Override        public void run() {            while (true) {                System.out.println(Thread.currentThread().getName() + "在运行。");            }        }    }}

Java 线程的生命周期

java.lang.Thread.State 中定义了 6 种不同的线程状态,在给定的一个时刻,线程只能处于其中的一个状态。 下图给出了这六种状态,注意中间的 Ready 和 Running 都属于 Runnable 就绪状态。jto28资讯网——每日最新资讯28at.com

jto28资讯网——每日最新资讯28at.com

以下是各状态的说明,以及状态间的联系:jto28资讯网——每日最新资讯28at.com

  • 新建(New) - 尚未调用 start 方法的线程处于此状态。此状态意味着:线程创建了但尚未启动。
  • 就绪(Runnable) - 已经调用了 start 方法的线程处于此状态。此状态意味着:线程已经在 JVM 中运行。但是在操作系统层面,它可能处于运行状态,也可能等待资源调度(例如处理器资源),资源调度完成就进入运行状态。所以该状态的可运行是指可以被运行,具体有没有运行要看底层操作系统的资源调度。
  • 阻塞(Blocked) - 此状态意味着:线程处于被阻塞状态。表示线程在等待 synchronized 的隐式锁(Monitor lock)。被 synchronized 修饰的方法、代码块同一时刻只允许一个线程执行,其他线程只能等待,即处于阻塞状态。当占用 synchronized 隐式锁的线程释放锁,并且等待的线程获得 synchronized 隐式锁后,就又会从 BLOCKED 转换到 RUNNABLE 状态。
  • 等待(Waiting) - 此状态意味着:线程无限期等待,直到被其他线程显式地唤醒。 阻塞和等待的区别在于,阻塞是被动的,它是在等待获取 synchronized 的隐式锁。而等待是主动的,线程通过调用 Object.wait 等方法进入。
  • 定时等待(Timed waiting) - 此状态意味着:无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒,线程通过调用设置了 Timeout 参数的Object.wait 等方法进入。
  • 终止(Terminated) - 线程执行完 run 方法,或者因异常退出了 run 方法。此状态意味着:线程结束了生命周期。

下面这张图更生动地展示了线程状态切换的时机和触发条件(图片来自网络,出处下方饮用链接1)。jto28资讯网——每日最新资讯28at.com

jto28资讯网——每日最新资讯28at.com

引用链接:jto28资讯网——每日最新资讯28at.com

  • https://dunwu.github.io/javacore/concurrent/Java%E7%BA%BF%E7%A8%8B%E5%9F%BA%E7%A1%80.html
  • https://www.cnblogs.com/pcheng/p/6905340.html

本文链接:http://www.28at.com/showinfo-26-51228-0.html老后端被借调去写Java了,含泪总结的Java多线程编程基础

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: PHP老矣,尚能饭否?

下一篇: 如何快速分析软件运行瓶颈在哪里?推荐Linux下的一个强大命令工具

标签:
  • 热门焦点
  • 一加Ace2 Pro真机揭晓 钛空灰配色质感拉满

    一加Ace2 Pro真机揭晓 钛空灰配色质感拉满

    终于,在经过了几波预热之后,一加Ace2 Pro的外观真机图在网上出现了。还是博主数码闲聊站曝光的,这次的外观设计还是延续了一加11的方案,只是细节上有了调整,例如新加入了钛空灰
  • 在线图片编辑器,支持PSD解析、AI抠图等

    在线图片编辑器,支持PSD解析、AI抠图等

    自从我上次分享一个人开发仿造稿定设计的图片编辑器到现在,不知不觉已过去一年时间了,期间我经历了裁员失业、面试找工作碰壁,寒冬下一直没有很好地履行计划.....这些就放在日
  • 三万字盘点 Spring 九大核心基础功能

    三万字盘点 Spring 九大核心基础功能

    大家好,我是三友~~今天来跟大家聊一聊Spring的9大核心基础功能。话不多说,先上目录:图片友情提示,本文过长,建议收藏,嘿嘿嘿!一、资源管理资源管理是Spring的一个核心的基础功能,不
  • 使用LLM插件从命令行访问Llama 2

    使用LLM插件从命令行访问Llama 2

    最近的一个大新闻是Meta AI推出了新的开源授权的大型语言模型Llama 2。这是一项非常重要的进展:Llama 2可免费用于研究和商业用途。(几小时前,swyy发现它已从LLaMA 2更名为Lla
  • 一个注解实现接口幂等,这样才优雅!

    一个注解实现接口幂等,这样才优雅!

    场景码猿慢病云管理系统中其实高并发的场景不是很多,没有必要每个接口都去考虑并发高的场景,比如添加住院患者的这个接口,具体的业务代码就不贴了,业务伪代码如下:图片上述代码有
  • Temu起诉SHEIN,跨境电商战事升级

    Temu起诉SHEIN,跨境电商战事升级

    来源 | 伯虎财经(bohuFN)作者 | 陈平安日前据外媒报道,拼多多旗下跨境电商平台Temu正对竞争对手SHEIN提起新诉讼,诉状称Shein&ldquo;利用市场支配力量强迫服装厂商与之签订独家
  • 华为将推出盘古数字人大模型 可帮助用户12小时完成数字人生成

    华为将推出盘古数字人大模型 可帮助用户12小时完成数字人生成

    在今日举行的2023年华为云数字文娱AI创新峰会上,华为云全球Marketing与销售服务总裁石冀琳表示,华为云将在后续推出盘古数字人大模型,可帮助用户12小
  • 华为HarmonyOS 4.0将于8月4日发布 或搭载AI大模型技术

    华为HarmonyOS 4.0将于8月4日发布 或搭载AI大模型技术

    华为宣布HarmonyOS4.0将于8月4日正式发布。此前,华为已经针对开发者公布了HarmonyOS4.0,以便于开发者提前进行适配,也因此被曝光出了一些新系统的特性
  • DRAM存储器10月价格下跌,NAND闪存本月价格与上月持平

    DRAM存储器10月价格下跌,NAND闪存本月价格与上月持平

    10月30日,据韩国媒体消息,自今年年初以来一直在上涨的 DRAM 存储器的交易价格仅在本月就下跌了近 10%,此次是全年首次降价,而NAND 闪存本月价格与上月持平。市
Top