Java并发编程 JUC 线程的创建

进程和线程的区别

进程:进程是cpu资源分配的最小单位,有自己独立的内存空间

线程:线程是cpu调度的最小单位,共享进程的内存空间,一个进程在运行的过程中可以产生多个进程,线程在切换时消耗的资源远小于进程的切换

在Java中,创建一个线程的方法有很多种,可以通过复写父类的run()方法进行创建,也可以创建Runnable对象进行创建

import lombok.extern.slf4j.Slf4j;

/**
 * Thread 测试类
 */

@Slf4j(topic = "c.ThreadTest1")
public class ThreadTest1 {
    public static void main(String[] args) {
        Thread t1 = new Thread("First Thread"){
            @Override
            public void run() {
                log.debug("t1 is running");
            }
        };
        Runnable task1 = new Runnable() {
            @Override
            public void run() {
                log.debug("t2 is running");
            }
        };
        Runnable task2 = () -> log.debug("task2 is running");//lambda
        Thread t2 = new Thread(task1);
        Thread t3 = new Thread(task2,"Third Thread");
        t2.setName("Second Thread");
        t1.start();
        t2.start();
        t3.start();

        log.debug("main is running");
    }
}

执行结果:

16:28:47.179 [main] DEBUG c.ThreadTest1 - main is running
16:28:47.179 [Second Thread] DEBUG c.ThreadTest1 - t2 is running
16:28:47.179 [Third Thread] DEBUG c.ThreadTest1 - task2 is running
16:28:47.179 [First Thread] DEBUG c.ThreadTest1 - t1 is running

Process finished with exit code 0

查看Runnable源码,我们可以发现,Runnable接口中只有一个抽象方法run(),@FunctionalInterface注解表明的方法都可以使用lambda表达式进行简化

@FunctionalInterface//只有一个抽象方法的情况下使用
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

在JVM虚拟机中,每一个线程都会对应一个栈,每一个线程的栈空间都是相互独立的,线程的一个方法对应栈中的一个栈帧。

JVM的内存结构:

  1. 程序计数器

  程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。每个线程都有一个独立的程序计数器,它的作用是记录当前线程执行的位置,以便在发生线程切换时恢复执行位置。

  1. Java虚拟机栈

  Java虚拟机栈是线程私有的,它的生命周期与线程相同。每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。当方法执行完毕后,对应的栈帧会被弹出,局部变量表等信息也会被销毁。

  1. 本地方法栈

  本地方法栈与Java虚拟机栈类似,不同的是它为本地方法服务。本地方法是指使用其他语言(如C、C++)编写的方法,它们不会像Java方法那样被编译成字节码,而是直接被编译成机器码。本地方法栈的作用是为本地方法提供内存空间。

  1. Java堆

  Java堆是Java虚拟机所管理的内存中最大的一块,它是被所有线程共享的一块内存区域。Java堆的作用是存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆是垃圾收集器管理的主要区域,因此也被称为GC堆。

  1. 方法区

  方法区也是被所有线程共享的一块内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区也被称为永久代,但在JDK8之后,永久代被移除,取而代之的是元空间。

start()和run()

  直接调用 t1.run():14:53:20.755 [main] DEBUG c.ThreadTest1 - t1 is running,可以很清晰的看到,这是main()主线程在执行方法,并不能起到多线程并发的作用,调用t1.start():14:53:20.755 [First Thread] DEBUG c.ThreadTest1 - t1 is running,可以看到,这才是t1线程启动执行方法

 

Java线程的优先级

  在Java中,我们可以手动的调整线程的优先级,但是,具体的优先级执行情况还是由操作系统决定,Java中手动调整的优先级仅供参考,通过Thread的setPriority()方法可以调整线程的优先级,Java中线程的优先级从1-10,默认为5:

    /**
     * The minimum priority that a thread can have.
     */
    public static final int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public static final int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public static final int MAX_PRIORITY = 10;

  查看setPriority()源码:

    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

 

posted @ 2023-06-08 17:21  k3ruanren  阅读(30)  评论(0)    收藏  举报