栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

一、线程基础知识

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一、线程基础知识

目录

1、Java多线程概念

1.1 并发和并行

1.1.1 并发

1.1.2 并行

1.2 进程&线程&管程 

1.2.1 进程

1.2.2 线程

1.2.3 管程

2、用户线程&守护线程

2.1 用户线程

2.2 守护线程

3、线程.start() 解读

4、实现多线程的三种方式(这里只说普通方式)

4.1 继承Thread类,重写run方法

4.2 实现Runnable接口,重写run方法

4.3  实现Callable接口,重写call方法


1、Java多线程概念

  1.1 并发和并行

    1.1.1 并发

        是在同一实体上的多个事件,是在同一台处理器上“同时”处理多个任务,同一时刻,其实是只有一个事件在发生。用生活的例子表达:我们泡面,先做水,然后撕泡面的调料,然后用水泡面。这些事(做水、撕调料包、泡面)其实都是一个人干的。

    1.1.2 并行

        是在不同实体上的多个事件,是在多台处理器上处理多个任务,同一时刻,大家都真的在做事情,你做你的,我做我的。比如一个货运站,两个司机,将货物送往不同的目的地,他们之间没有任务直接关系。              

  1.2 进程&线程&管程 

    1.2.1 进程

        系统中运行一个应用程序就是一个进程,每一个进程都有它自己的内存空间和系统资源。

    1.2.2 线程

        轻量级进程,在同一个进程内基本会有一个或多个线程,是大多数操作系统进行调度的基本单元。

    1.2.3 管程

        Monitor(监视器),也就是我们平常说的锁。

        Monitor其实是一种同步机制,他的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码。

        JVM中同步时基于进入和退出监视器对象来实现的,每个对象的对象头中标记。

        注:Monitor后续会着重去研究,到时候会将连接放到这里。(2022/070/25)

2、用户线程&守护线程

        Java线程分为用户线程和守护线程

  2.1 用户线程

        是系统的工作线程,它会完成这个程序需要完成的业务操作。如果用户线程不完成,则程序会一直执行下去。(注意:这里一定要用main方法入口,不要用@Test)

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"t 开始运行,"+(Thread.currentThread().isDaemon() ? "守护线程":"用户线程"));
            for(;;){

            }
        },"自定义线程");
        // 默认是 false
        t.setDaemon(false);
        t.start();
        System.out.println("----------main线程运行完毕");
}

        这里可以看出程序无法退出,因为自定义线程是用户线程,内部是死循环,一直处于运行状态,无法结束。

2.2 守护线程

        是一种特殊的线程,为其他线程服务的,在后台默默完成一些系统性的服务,比如垃圾回收线程。当系统只身下守护线程的时候,java虚拟机会自动退出。

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"t 开始运行,"+(Thread.currentThread().isDaemon() ? "守护线程":"用户线程"));
            for(;;){

            }
        },"自定义线程");
        // 默认是 false
        t.setDaemon(true);
        t.start();
        System.out.println("----------main线程运行完毕");
    }

  • 守护线程作为一个服务线程,没有服务对象(用户线程)就没有必要继续运行了,如果用户线程全部结束了,意味着程序可以已经完成业务操作,系统可以退出。系统只剩下守护线程时,Java虚拟机会自动退出。
  • SetDaemon(true)方法必须在start()之前设置,否则报IlleaglThreadStateException异常。

3、线程.start() 解读
public static void main(String[] args) {
        Thread t1 = new Thread(() ->{
        },"t1");
        t1.start();
}

.start()

//start
    public synchronized void start() {
        
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                
            }
        }
    }
// start0是一个native方法
private native void start0();

我们可以看到start0方法被native修饰着。(native关键字告诉编译器-JVM调用该方法在外部定义,这里指的是C),我们可以通过查看OpenJDK查看源码:OpenJDK Mercurial Repositories

 Thread.c源码位置

​

我们看到 start0 其实就是JVM_StartThread。

​

jvm.cpp源码位置

 jvm.cpp位置

 jvm.cpp源码

 thread.cpp源码位置

 

 这里可以看到动用了操作系统的线程启动,os::start_thread(thread)

4、实现多线程的三种方式(这里只说普通方式)
  • 继承Thread类,重写run方法,无返回值;
  • 实现Runnable接口,重写run方法,无返回值;
  • 实现Callable接口,重写call方法,有返回值;

4.1 继承Thread类,重写run方法
public class ExtendsThreadTest extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 执行");
    }
    public static void main(String[] args) {
        Thread t1 = new ExtendsThreadTest();
        Thread t2 = new ExtendsThreadTest();
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}

4.2 实现Runnable接口,重写run方法

        这样可以使用Runnable实现类中的成员变量

public class RunnableThreadTest implements Runnable {
    
    private Integer threadNum = 0;

    @Override
    public void run() {
        threadNum++;
        System.out.println(Thread.currentThread().getName() + " 执行,当前有" + threadNum + "线程已执行过了");
    }
    @SneakyThrows
    public static void main(String[] args) {
        RunnableThreadTest runnableThread = new RunnableThreadTest();
        Thread t1 = new Thread(runnableThread);
        t1.setName("线程1");
        Thread t2 = new Thread(runnableThread);
        t2.setName("线程2");
        t1.start();
        // 用来放慢线程执行速度
        Thread.sleep(1000);
        t2.start();
    }
}

4.3  实现Callable接口,重写call方法
public class CallableThreadTest implements Callable {
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName() + " 执行");
        return Thread.currentThread().getName() + " 返回值";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableThreadTest callableThread = new CallableThreadTest();
        FutureTask futureTask = new FutureTask<>(callableThread);
        Thread t1 = new Thread(futureTask);
        t1.setName("线程1");
        t1.start();
        String s = futureTask.get();
        System.out.println(s);
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1028761.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号