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);
        }
    }
}

运行结果

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

相关推荐
brrdg_sefg5 分钟前
gitlab代码推送
java
hanbarger28 分钟前
mybatis框架——缓存,分页
java·spring·mybatis
cdut_suye35 分钟前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
苹果醋31 小时前
2020重新出发,MySql基础,MySql表数据操作
java·运维·spring boot·mysql·nginx
小蜗牛慢慢爬行1 小时前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
azhou的代码园1 小时前
基于JAVA+SpringBoot+Vue的制造装备物联及生产管理ERP系统
java·spring boot·制造
wm10432 小时前
java web springboot
java·spring boot·后端
smile-yan2 小时前
Provides transitive vulnerable dependency maven 提示依赖存在漏洞问题的解决方法
java·maven
老马啸西风2 小时前
NLP 中文拼写检测纠正论文-01-介绍了SIGHAN 2015 包括任务描述,数据准备, 绩效指标和评估结果
java
Earnest~2 小时前
Maven极简安装&配置-241223
java·maven