前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java】14 多线程

【Java】14 多线程

作者头像
Demo_Null
发布2020-09-28 11:07:13
4040
发布2020-09-28 11:07:13
举报
文章被收录于专栏:Java 学习Java 学习

Java 使用 java.lang.Thread 类代表线程,所有的线程对象都必须是 Thread 类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java 使用线程执行体来代表这段程序流。

一、 线程

1.1 相关概念

并发:在操作系统中,安装了多个程序,并发指的是在一段时间内宏观上有多个程序同时运行,这在单 CPU 系统中,每一时刻只能有一道程序执行,即微观上这些程序是分时的交替运行,只不过是给人的感觉是同时运行,那是因为分时交替运行的时间是非常短的。 并行:在多个 CPU 系统中,这些可以并发执行的程序可以分配到多个处理器上(CPU),实现多任务并行执行,即利用每个处理器来处理一个可以并发执行的程序,这样多个程序便可以同时执行。目前电脑市场上说的多核 CPU,便是多核处理器,核 越多,并行处理的程序越多,能大大的提高电脑运行的效率。

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

1.2 继承 Thread 类创建线程

1.2.1 使用方式

① 定义 Thread 类的子类,并重写该类的 run( ) 方法。 ② 创建 Thread 子类的实例,即创建了线程对象。 ③ 调用线程对象的 start( ) 方法来启动该线程。

1.2.2 构造方法

public Thread( ):分配一个新的线程对象 。 public Thread(String name):分配一个新的线程对象并指定名称 。 public Thread(Runnable target):分配一个带有指定目标的新的线程对象 。 public Thread(Runnable target,String name):分配一个带有指定目标的新的线程对象并指定名称。

1.2.3 常用方法

方法名

说明

String getName( )

获取当前线程名称

void start( )

此线程开始执行 ,JVM 调用此线程的 run 方法

void run( )

此线程要执行的任务在此处定义代码

static void sleep(long millis)

使当前正在执行的线程暂停停止执行指定的毫秒数

static Thread currentThread( )

返回对当前正在执行的线程对象的引用

1.2.4 示例
代码语言:javascript
复制
//  自定义线程
public class MyThread extends Thread {
    /**
     * 重写run方法,完成该线程执行的逻辑
     * 该 run( ) 方法的方法体就代表了线程需要完成的任务,因此把 run( ) 方法称为线程执行体。
     */
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("MyThread 线程 正在执行: " + i);
        }
    }
}

-----------------------------------------------------------------------------------


// 测试类
public class Test {
    public static void main(String[] args) {
        // 创建自定义线程对象
        MyThread mt = new MyThread();
        // 开启新线程
        mt.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main 线程 正在执行: " + i);
        }
    }
}
在这里插入图片描述
在这里插入图片描述

1.3 实现 Runnable 接口创建线程

1.3.1 使用方式

① 定义 Runnable 接口的实现类,并重写该接口的 run( ) 方法。 ② 创建 Runnable 实现类的实例,并以此实例作为 Thread 的 target 来创建 Thread 对象,该 Thread 对象才是真正的线程对象。 ③ 调用线程对象的 start( ) 方法来启动线程。

1.3.2 示例
代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        // 通过匿名内部类创建 Runnable 实现类对象
        Runnable myRunnable = new Runnable() {
		    @Override
		    public void run() {
		        for (int i = 0; i < 100; i++) {
		            System.out.println(Thread.currentThread().getName() + " 正在执行: " + i);
		        }
		    }
		};

		// 通过 MyRunnable 创建线程
        Thread thread = new Thread(myRunnable);
        thread.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main 线程 正在执行: " + i);
        }
    }
}
在这里插入图片描述
在这里插入图片描述
1.3.3 注意

   通过实现 Runnable 接口,使该类有了多线程类的特征。run( ) 方法是多线程程序的一个执行目标。所有的多线程代码都在 run( ) 方法里面。Thread 类实际上也是实现了 Runnable 接口的类。    在启动的多线程的时候,需要先通过 Thread 类的构造方法 Thread(Runnable target) 构造出对象,然后调用 Thread 对象的 start( ) 方法来运行多线程代码。实际上所有的多线程代码都是通过运行 Thread 的 start( ) 方法来运行的。因此,不管是继承 Thread 类还是实现 Runnable 接口来实现多线程,最终还是通过 Thread 的对象的 API 来控制线程。    启动线程使用 start( ) 方法,而不是 run( ) 方法!永远不要调用线程对象的 run( ) 方法!调用 start( ) 方法来启动线程,系统会把该 run( ) 方法当成线程执行体来处理;但如果直接调用线程对象的 run( ) 方法,则 run( ) 方法立即就会被执行,而且在 run( ) 方法返回之前其他线程无法并发执行,也就是说,如果直接调用线程对象的 run( ) 方法,系统把线程对象当成一个普通对象,而 run( ) 方法也是一个普通方法,而不是线程执行体。

1.4 使用 Callable 和 Future 创建线程

   Java 提供了 Callable 接口,该接口像是 Runnable 接口的增强版,Callable 接口有一个 call( ) 方法可以作为线程执行体,但 call( ) 方法比 run( ) 方法功能更强大。    ♘ call( ) 方法可以有返回值。    ♘ call( ) 方法可以声明抛出异常。 我们希望可以提供一个 Callable 对象作为 Thread 的 target,而该线程的线程执行体就是该 Callable 对象的 call( ) 方法。但是 Callable 它不是 Runnable 接口的子接口,所以 Callable 对象不能直接作为 Thread 的 target。    Java 为我们提供了 Future 接口来解决这个问题,使用 Future 接口来代表 Callable 接口里 call( ) 方法的返回值,并为 Future 接口提供了一个 FutureTask 实现类,该实现类实现了 Future 接口,并实现了 Runnable 接口可以作为 Thread 类的 target。

1.4.1 使用方式

① 创建 Callable 接口的实现类,并实现 call( ) 方法,该 call( ) 方法将作为线程执行体,且该 call( ) 方法有返回值,再创建 Callable 实现类的实例。 ② 使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call( ) 方法的返回值。 ③ 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。 ④调用 FutureTask 对象的 get( ) 方法来获得子线程执行结束后的返回值。

1.4.2 示例
代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {

        // 创建 Callable 匿名内部类对象
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + "---" + i);
                }
                return "我执行完了";
            }
        };

        // 使用 FutureTask 来包装 Callable
        FutureTask<String> futureTask = new FutureTask<>(callable);

        // 通过 FutureTask 创建线程
        Thread thread = new Thread(futureTask, "我是通过 Callable 接口创建的线程");
        thread.start();

        try {
            // 打印线程返回值
            System.out.println(futureTask.get());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
在这里插入图片描述
在这里插入图片描述

二、线程同步

2.1 线程安全

   如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

在这里插入图片描述
在这里插入图片描述
2.1.1 线程不安全示例
代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {
        // 通过匿名内部类创建 Runnable 实例对象
        Runnable myRunnable = new Runnable() {
            // 总共 100 张票
            private int ticket = 100;

            @Override
            public void run() {
                while (ticket > 0) {
                    //出 票 操作
                    try {
                        // 模拟出票时间
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 获取当前正在执行的线程名称
                    String name = Thread.currentThread().getName();

                    // 出票
                    System.out.println(name + "正在卖: " + ticket-- + " 张票");
                }
            }
        };

        // 通过 MyRunnable 创建线程
        Thread windows1 = new Thread(myRunnable, "窗口1");
        Thread windows2 = new Thread(myRunnable, "窗口2");
        Thread windows3 = new Thread(myRunnable, "窗口3");


        windows1.start();
        windows2.start();
        windows3.start();
    }
}
在这里插入图片描述
在这里插入图片描述

造成这种结果的原因就是一个线程在操作一个资源的同时,另一个线程也在操作这个资源。

2.2 线程同步

   当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写的操作,就容易出现线程安全问题。Java 提供了同步机制(synchronized)来解决线程不安全的问题。

2.2.1 同步代码块

   synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

语法

代码语言:javascript
复制
synchronized(同步锁){
	需要同步的代码
}

注意   锁对象可以是对象、this还可以使用该类的字节码文件,但是多个线程使用的锁对象必须是同一个。   一个线程获取锁对象进入同步代码块时,其他进程就算获取了 CPU 执行权也无法进入同步代码块,只有等锁对象释放以后,获取到锁对象后才能访问。

示例

代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {

        // 通过匿名内部类创建 Runnable 实例对象
        Runnable myRunnable = new Runnable() {
            // 总共 100 张票
            private int ticket = 100;

            // 创建锁对象
            Object object = new Object();

            @Override
            public void run() {
                while (ticket > 0) {
                    synchronized (object) {
                        //出 票 操作
                        try {
                            // 模拟出票时间
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // 获取当前正在执行的线程名称
                        String name = Thread.currentThread().getName();

                        // 出票
                        System.out.println(name + "正在卖: " + ticket-- + " 张票");
                    }
                }
            }
        };

        // 通过 MyRunnable 创建线程
        Thread windows1 = new Thread(myRunnable, "窗口1");
        Thread windows2 = new Thread(myRunnable, "窗口2");
        Thread windows3 = new Thread(myRunnable, "窗口3");


        windows1.start();
        windows2.start();
        windows3.start();

    }
}
在这里插入图片描述
在这里插入图片描述

  为什么使用了同步代码块还是会出现超卖的现象,这是因为在 窗口1 线程在卖最后一张票的时候,另外两个线程进入 while 循环的时候 ticket = 1 > 0,等待拿到锁对象后直接执行同步代码块内代码,就卖出了 0 号、-1 号票,所以在写代码的时候一定要注意。

2.2.2 同步方法

   与同步代码块对应,Java 的多线程安全支持还提供了同步方法,同步方法就是使用 synchronized 关键字来修饰某个方法,则该方法称为同步方法。对于 synchronized 修饰的实例方法(非 static 方法)而言,无须显式指定锁对象,同步方法的锁对象是 this,也就是调用该方法的对象。

语法

代码语言:javascript
复制
修饰符 synchronized 返回值 方法名(参数列表) {
    //方法体
}

注意   synchronized 关键字可以修饰方法,可以修饰代码块,但不能修饰构造器、成员变量等。

示例

代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {

        // 通过匿名内部类创建 Runnable 实例对象
        Runnable myRunnable = new Runnable() {
            // 总共 100 张票
            private int ticket = 100;

            @Override
            public void run() {
                while (true) {
                    this.outTicket();
                }
            }

            public synchronized void outTicket() {
                if (ticket > 0) {
                    //出 票 操作
                    try {
                        // 模拟出票时间
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 获取当前正在执行的线程名称
                    String name = Thread.currentThread().getName();

                    // 出票
                    System.out.println(name + "正在卖: " + ticket-- + " 张票");
                }
            }
        };

        // 通过 MyRunnable 创建线程
        Thread windows1 = new Thread(myRunnable, "窗口1");
        Thread windows2 = new Thread(myRunnable, "窗口2");
        Thread windows3 = new Thread(myRunnable, "窗口3");


        windows1.start();
        windows2.start();
        windows3.start();

    }
}
在这里插入图片描述
在这里插入图片描述
2.2.3 Lock 锁

   java.util.concurrent.locks.Lock 机制提供了比 synchronized 代码块和 synchronized 方法更广泛的锁定操作,同步代码块/同步方法具有的功能 Lock 都有,除此之外更强大,更体现面向对象。    Lock 是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得 Lock 对象。在实现线程安全的控制中,比较常用的是 ReentrantLock(可重入锁)。使用该 Lock对象可以显式地加锁、释放锁。

常用方法

方法名

说明

public void lock( )

加同步锁

public void unlock( )

释放同步锁

示例

代码语言:javascript
复制
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test {

    public static void main(String[] args) {

        // 通过匿名内部类创建 Runnable 实例对象
        Runnable myRunnable = new Runnable() {
            // 总共 100 张票
            private int ticket = 100;

            Lock lock = new ReentrantLock();

            @Override
            public void run() {
                while (true) {
                    // 添加锁
                    lock.lock();
                    if (ticket > 0) {
                        //出 票 操作
                        try {
                            // 模拟出票时间
                            Thread.sleep(100);
                            // 获取当前正在执行的线程名称
                            String name = Thread.currentThread().getName();

                            // 出票
                            System.out.println(name + "正在卖: " + ticket-- + " 张票");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            // 释放锁
                            lock.unlock();
                        }
                    }
                }
            }
        };

        // 通过 MyRunnable 创建线程
        Thread windows1 = new Thread(myRunnable, "窗口1");
        Thread windows2 = new Thread(myRunnable, "窗口2");
        Thread windows3 = new Thread(myRunnable, "窗口3");


        windows1.start();
        windows2.start();
        windows3.start();

    }
}
在这里插入图片描述
在这里插入图片描述
2.2.4 死锁

   死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。比如,当线程 A 持有独占锁 a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 A B 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。

在这里插入图片描述
在这里插入图片描述

三、线程状态

3.1 线程七种状态

① new(新建):线程刚刚被创建,但是并未启动 ② Runnable(可运行):线程可以运行但是没有 CPU 执行权 ③ Running(运行):线程正在执行过程中 ④ Blocked(锁阻塞):线程无法获取到锁对象 ⑤ Waiting(无限等待):一个线程在等待另一个线程的唤醒 ⑥ Time Waiting(计时等待):线程等待 n 毫秒后自动唤醒 ⑦ Teminated(被终止):线程执行结束

在这里插入图片描述
在这里插入图片描述

3.2 线程间的通信

   多个线程并发执行时,在默认情况下 CPU 是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。也就是我们需要通过一定的手段使各个线程能有序的完成工作。而这种手段就是等待唤醒机制

3.2.1 常用方法

方法名

说明

void wait( )

等待另一个线程唤醒

void wait(long l)

线程等待 l 毫秒后自动被唤醒

void notify()

唤醒在等待中的一个线程,等待最久的优先被唤醒

void notifyAll( )

唤醒所有等待的线程

3.2.2 注意

   wait( ) 和 notify( ) 需要在同步代码块或者同步方法中使用,需要使用同一个锁对象(定义在 Object 中,任何一个类都可以使用)。    哪怕 notify( ) 只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步代码块内,而此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait( ) 方法之后的地方恢复执行。wait( ) 会释放锁而 sleep( ) 不会释放锁。


四、线程控制

4.1 jion 线程

   Thread 提供了让一个线程等待另一个线程完成的方法 join( ) 方法。当在某个程序执行流中调用其他线程的 join( ) 方法时,调用线程将被阻塞,直到被 join( ) 方法加入的 join( ) 线程执行完为止。即:在当前线程中 a 中,b 线程调用 join( ) 方法,那么,a 线程就会释放资源,让给 b 线程先执行,直到 b 线程执行完毕。

示例

代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {

        // 通过匿名内部类创建 Runnable 实例对象
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("我是 jion 线程" + i);
                }
            }
        };

        for (int i = 0; i < 10; i++) {
            if (7 == i) {
                try {
                    Thread thread = new Thread(myRunnable);
                    thread.start();
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println("main 在执行" + i);
        }

    }
}
在这里插入图片描述
在这里插入图片描述

4.2 后台线程

   有一种线程,它是在后台运行的,它的任务是为其他的线程提供服务,这种线程被称为“后台线程(Daemon Thread)”,又称为“守护线程”或“精灵线程”。JVM 的垃圾回收线程就是典型的后台线程。后台线程有个特征:如果所有的前台线程都死亡,后台线程会自动死亡。    调用 Thread 对象的 setDaemon(true) 方法可将指定线程设置成后台线程。当整个虚拟机中只剩下后台线程时,程序就没有继续运行的必要了,所以虚拟机也就退出了。

4.3 线程优先级

   每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会,而优先级低的线程则获得较少的执行机会。每个线程默认的优先级都与创建它的父线程的优先级相同,在默认情况下,main 线程具有普通优先级,由 main 线程创建的子线程也具有普通优先级。    Thread 类提供了setPriority(int newPriority)、getPriority( ) 方法来设置和返回指定线程的优先级,其中 setPriority(int newPriority) 方法的参数可以是一个整数,范围是1~10之间,也可以使用Thread类的三个静态常量: MAX PRIORITY:其值是 10 MIN PRIORITY:其值是 1 NORM PRIORITY:其值是 5,main 线程的优先级就是 5 线程优先级越高,仅代表获得执行的机会越多,不代表一定会先执行。


五、线程池

   如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。在 Java 中提供了线程池来解决这一问题,线程池就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。

5.1 线程池的使用

   Java 里面线程池的顶级接口是 java.util.concurrent.Executor,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 java.util.concurrent.ExecutorService。要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在 java.util.concurrent.Executors 线程工厂类里面提供了一些静态工厂,生成一些常用的线程池。官方建议使用 Executors 工程类来创建线程池对象。 static ExecutorService newCachedThreadPool( ):创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中。 static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数的线程池。 static ExecutorService newSingleThreadExecutor( ):创建一个只有单线程的线程池,它相当于调用 newFixedThreadPool( ) 方法时传入参数为1。 获取到了一个线程池 ExecutorService 对象,那么怎么使用呢,在这里定义了一个使用线程池对象的方法: Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行 用完一个线程池后,应该调用该线程池的 shutdown( ) 方法,该方法将启动线程池的关闭序列,调用 shutdown( ) 方法后的线程池不再接收新任务,但会将以前所有已提交任务执行完成。

5.1.1 线程池的使用步骤

① 调用 Executors 类的静态工厂方法创建一个 ExecutorService 对象,该对象代表一个线程池。 ② 创建 Runnable 实现类或 Callable 实现类的实例,作为线程执行任务。 ③ 调用 ExecutorService 对象的 submit( ) 方法来提交 Runnable 实例或 Callable 实例。

5.1.2 示例
代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {

        // 通过匿名内部类创建 Runnable 实例对象
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + ": " + i);
                }
            }
        };

        // 创建线程池
        ExecutorService service = Executors.newFixedThreadPool(2);

        // 提交线程任务
        // submit 方法调用结束后,线程并不关闭,而是将使用完的线程又归还到了线程池中
        service.submit(myRunnable);
        service.submit(myRunnable);

        // 关闭线程池
        service.shutdown();
    }
}
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、 线程
    • 1.1 相关概念
      • 1.2 继承 Thread 类创建线程
        • 1.2.1 使用方式
        • 1.2.2 构造方法
        • 1.2.3 常用方法
        • 1.2.4 示例
      • 1.3 实现 Runnable 接口创建线程
        • 1.3.1 使用方式
        • 1.3.2 示例
        • 1.3.3 注意
      • 1.4 使用 Callable 和 Future 创建线程
        • 1.4.1 使用方式
        • 1.4.2 示例
    • 二、线程同步
      • 2.1 线程安全
        • 2.1.1 线程不安全示例
      • 2.2 线程同步
        • 2.2.1 同步代码块
        • 2.2.2 同步方法
        • 2.2.3 Lock 锁
        • 2.2.4 死锁
    • 三、线程状态
      • 3.1 线程七种状态
        • 3.2 线程间的通信
          • 3.2.1 常用方法
          • 3.2.2 注意
      • 四、线程控制
        • 4.1 jion 线程
          • 4.2 后台线程
            • 4.3 线程优先级
            • 五、线程池
              • 5.1 线程池的使用
                • 5.1.1 线程池的使用步骤
                • 5.1.2 示例
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档