Java之线程篇一

目录

如何理解进程?

进程和线程的区别

线程的优点

线程的缺点

线程异常

线程用途

创建线程

方法一:继承Thread类,重写run()

观察线程

小结

[方法二: 实现Runnable接口,重写run()](#方法二: 实现Runnable接口,重写run())

方法三:继承Thread类,重写run(),使用匿名内部类

方法四:实现Runnable接口,重写run(),使用匿名内部类

方法五:使用lambda表达式


如何理解进程?

用户视角:内核数据结构+对应的代码和数据!

内核视角:承担分配系统资源的实体!

进程和线程的区别

进程是包含线程的,每个进程至少有一个线程,即主线程;

进程和进程之间不共享内存空间,同一个进程的线程之间共享同一个内存空间;

进程是系统分配资源的最小单位,线程是系统调度的最小单位;

线程在进程内部执行;

线程的创建,切换及终止效率更高;

进程有自己的内存地址空间,线程只独享指令流执行的必要资源,如寄存器和栈;

由于同一进程的各线程间共享内存和文件资源,可以不通过内核进行直接通信。

线程的优点

创建一个新线程的代价要比创建一个新进程小得多;

与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多;

线程占用的资源要比进程少很多;

能充分利用多处理器的可并行数量;

在等待慢速 I/O 操作结束的同时,程序可执行其他的计算任务;

计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现;

I/O 密集型应用,为了提高性能,将 I/O 操作重叠。线程可以同时等待不同的 I/O 操作。

线程的缺点

性能损失

一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型,线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。

健壮性降低

编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。

缺乏访问控制

进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。

编程难度提高

编写与调试一个多线程程序比单线程程序困难得多

线程异常

因为创建的新线程,与主线程共用地址空间,页表等,所以新线程出现异常就会引起整个线程组异常。

单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃。

线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出 。

线程用途

合理的使用多线程,能提高 CPU 密集型程序的执行效率

合理的使用多线程,能提高 IO 密集型程序的用户体验(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现)

创建线程
方法一:继承Thread类,重写run()

代码

java 复制代码
class MyThread extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class Demo01 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new MyThread();
        t.start();
        while(true){
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}

运行结果

我们会发现,两个线程不分先后顺序的不断打印。

观察线程

使用JDK自带的工具jconsole.exe进行观察线程,以"管理员方式运行"

观察到的main线程

观察到我们创建的Thread线程

小结

Thread类里面的run()方法是线程的入口方法,描述了线程具体要做什么任务;

start()和run()都是Thread类的成员方法;

start()则是真正调用了系统API,在系统中创建出线程,让线程再调用run().

方法二: 实现Runnable接口,重写run()

代码

java 复制代码
class MyRunnable implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class Demo02 {
    public static void main(String[] args) throws InterruptedException {
        Runnable runnable=new MyRunnable();
        Thread t=new Thread(runnable);
        t.start();

        while(true){
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}

运行结果

我们会发现,两个线程不分先后顺序的不断打印。

方法三:继承Thread类,重写run(),使用匿名内部类

代码

java 复制代码
public class Demo03 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(){
            @Override
            public void run() {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        
        t.start();
        while(true){
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}

运行结果

我们会发现,两个线程不分先后顺序的不断打印。

方法四:实现Runnable接口,重写run(),使用匿名内部类

代码

java 复制代码
public class Demo04 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        t.start();

        while(true){
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}

运行结果

我们会发现,两个线程不分先后顺序的不断打印。

方法五:使用lambda表达式

代码

java 复制代码
public class Demo05 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            while(true){
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();

        while(true){
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}

运行结果

我们会发现,两个线程不分先后顺序的不断打印。

相关推荐
码农研究僧10 分钟前
Java或者前端 实现中文排序(调API的Demo)
java·前端·localecompare·中文排序·collator
Chase-Hart10 分钟前
【每日一题】LeetCode 7.整数反转(数学)
java·数据结构·算法·leetcode·eclipse
四角小裤儿儿17 分钟前
Java数据结构(十一)——归并排序、计数排序
java·数据结构·排序算法
guangzhi063324 分钟前
JVM本地方法栈
java·jvm·面试
akhfuiigabv29 分钟前
使用LangChain创建简单的语言模型应用程序【快速入门指南】
java·python·语言模型·langchain
忘却的纪念36 分钟前
基于SpringBoot的考研资讯平台设计与实现
java·spring boot·spring
.生产的驴37 分钟前
SpringBoot 消息队列RabbitMQ死信交换机
java·spring boot·后端·rabbitmq·java-rabbitmq
振华OPPO39 分钟前
我的5周年创作纪念日,不忘初心,方得始终。
android·java·android studio·安卓·安卓app
抚月code41 分钟前
Java线程池
java
IT枫斗者1 小时前
集合工具类
java·linux·数据库·windows·算法·microsoft