进程

进程的定义:进程是操作系统分配资源的基本单位。每个进程都有自己独立的内存空间和系统资源。

进程的独立性:进程之间是相互独立的,一个进程的崩溃不会影响到其他进程。

java中的体现:在Java中,每个运行的JVM实例就是一个进程。

也就是是说:咋们自己的java程序就是一个进程。 我们可以把工厂看作进程。流水线看作线程【好理解】

进程开销较大: 创建和销毁进程的开销较大

线程

线程的定义: 线程是进程内的执行单元,一个进程可以包含多个线程,所有线程共享进程的内存和资源。

1个进程中可以包含多个线程。

1个进程中至少有一个线程

线程开销较小:线程的创建和切换开销较小

进程与线程的区别

特性	           进程	                         线程
资源分配 独立的内存和系统资源 共享进程的内存和资源
创建开销 较大 较小
通信方式 进程间通信(IPC) 直接共享内存
独立性 进程间相互独立 线程间相互依赖
崩溃影响 一个进程崩溃不会影响其他进程 一个线程崩溃可能导致整个进程崩溃

java默认就会产生一个进程

java在运行的时候默认就会产生一个进程(在Java中,每个运行的JVM实例就是一个进程)

这个进程会有一个主线程,代码都在主线程中执行

获取当前线程的名称

package part;
public class Java01 {
// main方法,运行在main线程中
public static void main(String[] args) {
// 线程: Thread就是线程类
// Thread.currentThread() 获取当前正在运行的线程
// getName获取线程的名称
System.out.println(Thread.currentThread().getName()); // main
}
}

创建1个自定义线程,并启动

package part;
public class Java01 {
public static void main(String[] args) {
// 线程: Thread就是线程类
// Thread.currentThread() 获取当前正在运行的线程
// getName获取线程的名称
System.out.println(Thread.currentThread().getName()); // main // 创建1个线程对象
Thread t1 = new MyThread();
// 开始启动这个线程
t1.start();
}
} class MyThread extends Thread {
// ctrl+o可以重写
@Override
public void run() {
// 输出 线程名称:Thread-0
System.out.println("线程名称:"+Thread.currentThread().getName());
}
}

为啥先执行输出的是main 然后才是Thread-0

因为main线程最初进开始了,它没有准备时间。直接就开始了。

而我们的Thread-0需要准备时间

线程的生命周期7种

https://blog.csdn.net/weixin_46703995/article/details/131263544 [Java线程生命周期详解]参考的这里

线程的 7 种状态,其中1,2,3,7肯定是会有的。4,5,6可能不会出现的

1.新建状态(New): 当我们创建一个新的线程实例时,线程就处于新建状态。

这时候线程的start()方法还未被调用,线程对象还未开始执行。

在这个状态下,Java虚拟机(JVM)已经为此线程分配了必要的内存。

Thread t = new Thread(); // 线程此时处于:新建状态(New)

2.就绪状态(Runnable):当线程对象调用了start()方法后,该线程就处于就绪状态。

这个状态的线程位于可运行线程池中,等待被线程调度选中,获得CPU的使用权。

Thread t = new Thread(); // 线程此时处于新建状态(New)
t.start(); // 线程此时处于:就绪状态(Runnable)

3.运行状态(Running):线程获取到CPU时间片后,就进入运行状态,开始执行run()方法中的代码。

值得注意的是,代码执行的实际速度和效率与处理器的速度以及多核处理器的核数有关。

public void run() {
System.out.println("Thread is running.");
}
// 如果此时这个方法正在执行,那么线程就处于Running状态

4.阻塞状态(Blocked): 当一个线程试图获取一个内部的对象锁(也就是进入一个synchronized块)

而该锁被其他线程持有,则该线程进入阻塞状态。

阻塞状态的线程在锁被释放时,将会进入就绪状态。

5.等待状态(Waiting):线程通过调用其自身的wait()方法、join()方法或LockSupport.park()方法

或者通过调用其他线程的join()方法,可以进入等待状态。

在等待状态的线程不会被分配CPU时间片,它们只能通过被其他线程显式唤醒进入就绪状态。

// 线程此时处于:等待状态(Waiting)
t.wait();
t.join();

6.超时等待状态(Timed Waiting): 当线程调用了sleep(long ms),wait(long ms),join(long ms)

或者LockSupport.parkNanos(), LockSupport.parkUntil()等具有指定等待时间的方法.

线程就会进入超时等待状态。当超时时间到达后,线程会自动返回到就绪状态。

// 线程此时处于:超时等待状态(Timed Waiting)
Thread.sleep(3000); // 单位是毫秒的哈

7.终止状态(Terminated): 当线程的run()方法执行完毕,或者线程中断,线程就会进入终止状态。在这个状态下,线程已经完成了它的全部工作。

// 当run()方法执行完毕,线程处于 Terminated 状态
public void run() {
System.out.println("Thread is running.");
}

并发执行:多个线程之间是独立的

并发执行:多个线程之间是独立的。

谁先抢到CPU的执行权,谁就先执行。

或者说:线程1和线程2我们不知道谁先执行。每次运行的结果可能都不一样

下面我们通过代码来解释

package part;
public class Java01 {
public static void main(String[] args) {
// 线程: Thread就是线程类
// Thread.currentThread() 获取当前正在运行的线程
// getName获取线程的名称
// 创建2个线程对象
Thread t1 = new MyThread1();
Thread t2 = new MyThread2();
// 开始这2个启动这个线程
t1.start();
t2.start();
System.out.println(Thread.currentThread().getName()); // main
}
} class MyThread1 extends Thread {
@Override
public void run() {
// 输出 线程名称:Thread-0
System.out.println("线程名称1:");
}
} class MyThread2 extends Thread {
@Override
public void run() {
// 输出 线程名称:Thread-0
System.out.println("线程名称2:");
}
}

出现的结果可能是: main--》 线程名称1--》 线程名称2

也可能是:main--》 线程名称2--》 线程名称1

也就是说:不知道线程1和线程2我们不知道谁先执行。

多个线程之间是独立的。谁先抢到CPU的执行权,谁就先执行。

串行执行: 多个线程连接成串,然后按照顺序去执行。但是先执行的不一定先完成。

package part;
public class Java01 {
public static void main(String[] args) {
// 线程: Thread就是线程类
// Thread.currentThread() 获取当前正在运行的线程
// getName获取线程的名称 // 创建2个线程对象
Thread t1 = new MyThread1();
Thread t2 = new MyThread2();
// 开始这2个启动这个线程
t1.start();
t2.start();
// 将线程连接成串,先执行t1线程,然后再t2线程,最后是main线程。
// 先执行的不一定先完成。再说一句:执行的不一定先完成
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()); // main
}
} class MyThread1 extends Thread {
@Override
public void run() {
// 输出 线程名称:Thread-0
System.out.println("线程名称1:");
}
} class MyThread2 extends Thread {
@Override
public void run() {
// 输出 线程名称:Thread-0
System.out.println("线程名称2:");
}
}

输出的结果可能是:线程名称2:》线程名称1:》main。

也可能是:线程名称1:》线程名称2:》main。

因为: 先执行的不一定先完成。

休眠 Thread.sleep(3000) 等待3s在执行后面的代码

package part;
public class Java01 {
public static void main(String[] args) {
// 线程: Thread就是线程类
try {
// sleep只和当前的类有关系。在哪一个线程中调用这个方法。哪个线程就会休眠。
Thread.sleep(3000); // 单位是毫秒的哈
// 上面的代码会等待3s,然后再执行
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("等3s在执行:Hello World");
}
}

每隔1s输出Hello World

package part;
public class Java01 {
public static void main(String[] args) {
while (true){
Thread thread = new Thread();
try {
thread.sleep(1000);
System.out.println("等待1s在输出");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

自定义线程类

1,所有的自定义线程类都应该是去继承 Thread 这个线程类。

2,重写线程类中的run方法

3,启动线程 start

创建2个线程,输出线程的名称

package part;
public class Java01 {
public static void main(String[] args) {
//创建线程对象
Thread t1 = new MyThread1();
// 启动线程
t1.start(); //创建线程对象
Thread t2 = new MyThread2();
// 启动线程
t2.start();
}
} // 1.继承线程类Thread
class MyThread1 extends Thread {
// 重写线程的run方法
@Override
public void run() {
// 输出 线程名称1
System.out.println("线程名称1");
}
} // 1.继承线程类Thread
class MyThread2 extends Thread {
// 重写线程的run方法
@Override
public void run() {
// 输出 线程名称2
System.out.println("线程名称2");
}
}

现在是在2个线程中去输出他们各自的线程名称。

通过这一段代码,我们发现有点复杂了。

怎么来优化一下呢?

我们只创建1个线程,通过传递的参数不同。输出不同的线程名称。

创建1个线程通过传递的参数不同输出不同的线程名称

package part;
public class Java01 {
public static void main(String[] args) {
//创建线程对象
Thread t1 = new MyThread1("线程1");
// 启动线程
t1.start();
}
} class MyThread1 extends Thread {
private String threadName;
// 创建一个构造方法,通过参数来进行输出不同的语句
public MyThread1(String name) {
threadName = name;
// 或者 this.threadName = name;
}
// 重写线程的run方法
@Override
public void run() {
System.out.println(threadName);
}
}

我们除了这种通过构造方法的方式还有其他方式吗?

其实是有的。我们在构建线程对象时,把逻辑传递给这个线程对象就可以。

语法就是: new Thread(()->{你的逻辑})

ps:与js的箭头函数有点相似

下面我们就来尝试一下

我们在构建线程对象时,把逻辑传递给这个线程对象

package part;
public class Java01 {
public static void main(String[] args) {
//创建线程对象
Thread t1 = new Thread(()-> {
System.out.println("我是线程1");
});
// 启动线程
t1.start();
}
}

构建线程对象传递实现了 Runnable的匿名类

构建线程对象时,可以传递实现了 Runnable(线程的就绪状态)接口的类的对象。一般使用匿名类

package part;
public class Java01 {
public static void main(String[] args) {
//创建线程对象,这里我们使用了 Runnable接口的匿名类
Thread t =new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行了哈哈");
}
});
// 开始启动线程的哈
t.start();
}
}

匿名类

在某些场景下,类的名称并不重要;我们只想使用类中的方法;

这个时候我们可以采用特殊语法;匿名类

匿名类是一种没有名字的内部类

匿名类可以直接嵌入到代码中,通常出现在需要直接创建对象并使用其行为的地方。

例如事件监听器、回调、或者某个接口的具体实现。

匿名类的语法形式如下:

new NiNameClass() {

// 方法实现或者具体的逻辑

};

匿名类的应用场景

1.实现接口:实现简单接口而不必创建单独的类。

2.继承类:临时重写父类的某个方法,适合做简单扩展。

3.处理事件: 在 GUI 编程中,匿名类经常用于事件监听器的实现。

4.线程执行:用于 Runnable 接口的快速实现,简化代码。

匿名类的局限性

虽然匿名类能够简化代码的编写,但在某些情况下它也有一定的局限性:

1,只能使用一次:匿名类是一次性使用的类,不能在其他地方重复使用。如果需要复用代码,还是需要定义一个具名类。

2,不能定义构造函数:匿名类无法定义自己的构造函数,但可以调用父类的构造函数。

3,代码可读性差:当匿名类逻辑复杂时,可读性可能较差,尤其是当类体过长、代码嵌套较深时,维护起来较为困难。

4.局部变量的限制:匿名类只能访问外部类的有效最终变量(即外部方法的局部变量在匿名类中未被修改),这也是 Java 的作用域限制之一。

尾声

准备开始学习java了。

今天学习的第七天,每天都会发文章,我要卷起来。

请小伙伴们监督我,奥利给

java中线程的创建方式-休眠-生命周期-工作方式的更多相关文章

  1. java中线程池创建的几种方式

    java中创建线程池的方式一般有两种: 通过Executors工厂方法创建 通过new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize ...

  2. 一步一步掌握java的线程机制(二)----Thread的生命周期

    之前讲到Thread的创建,那是Thread生命周期的第一步,其后就是通过start()方法来启动Thread,它会执行一些内部的管理工作然后调用Thread的run()方法,此时该Thread就是a ...

  3. Java多线程——线程的创建方式

    Java多线程——线程的创建方式 摘要:本文主要学习了线程的创建方式,线程的常用属性和方法,以及线程的几个基本状态. 部分内容来自以下博客: https://www.cnblogs.com/dolph ...

  4. Java多线程并发03——在Java中线程是如何调度的

    在前两篇文章中,我们已经了解了关于线程的创建与常用方法等相关知识.接下来就来了解下,当你运行线程时,线程是如何调度的.关注我的公众号「Java面典」了解更多 Java 相关知识点. 多任务系统往往需要 ...

  5. java中线程机制

    java中线程机制,一开始我们都用的单线程.现在接触到多线程了. 多线性首先要解决的问题是:创建线程,怎么创建线程的问题: 1.线程的创建: 四种常用的实现方法 1.继承Thread. Thread是 ...

  6. Java中线程的实现:

    Java中线程的实现: 一.线程简介: 实现的两种方式为: 1.Thread类 2.Runnable接口 都在java.lang中 都有共通的方法:public void run() 二.线程常用方法 ...

  7. @Scope注解设置创建bean的方式和生命周期

    1.1.1            Scope注解创建bean的方式和生命周期 作用 Scope设置对象在spring容器(IOC容器)中的生命周期,也可以理解为对象在spring容器中的创建方式. 取 ...

  8. Java中线程池,你真的会用吗?

    在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...

  9. 沉淀再出发:java中线程池解析

    沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...

  10. Java中线程和线程池

    Java中开启多线程的三种方式 1.通过继承Thread实现 public class ThreadDemo extends Thread{ public void run(){ System.out ...

随机推荐

  1. 记录一个Linux代码移植到Windows平台下的Visual Studio 2022的代码编码格式的问题

    一.前言 工作上与公司的前辈对接,他给了我一份在linux下面编写的代码压缩包,按照道理来说使用条件宏编译不同的windows和linux的API即可实现代码的通用.但是我在Visual Studio ...

  2. Java日志手机号脱敏工具类

    背景 在开发过程中,很容易将用户敏感信息,例如手机号码.身份证等,打印在日志平台.为了保护用户数据,又不影响日志的打印,需要将日志中的敏感信息进行脱敏. 效果 没看明白,强烈建议 pull项目,执行一 ...

  3. C# 企业微信消息推送对接,实现天气预报推送

    C# 企业微信消息推送对接,实现天气预报推送 迷恋自留地 准备工作 需要获取的东西1. 企业Id,2.应用secret 和 应用ID 获取企业id 注册完成后,在我的企业=>企业信息=>最 ...

  4. nvm切换版本报exec: “cmd”: executable file not found in %PATH% 问题

    由于也是第一次用,出了个这报错懵了 搜了下也没个准确的解决办法(也可能是问题太简单),有的说可能是cmd变量没配好,检查了一遍没问题 后来想到报的是cmd,而cmd存储位置在 C:\Windows\S ...

  5. sqlserver配置分发实现主备

    方案总体说明 本方案采用"发布-订阅模式" 由主服务器进行发布消息,备份服务器进行订阅 当主服务器数据发生变更时,就会发布消息,备份服务器读取消息进行同步更新,中间过程延迟比较短. ...

  6. 从英库(Engkoo)输入法吐槽

    今天整理文件的时候发现在 OneDrive 的根目录还有一个 EngkooPinyin 的文件夹,看配置文件更新已经是 2014 年 3 月了.当时微软出这个输入法的时候,感觉非常好用,然后满怀热情给 ...

  7. 第1章04节 | 常见开源OLAP技术架构对比

    https://zhuanlan.zhihu.com/p/266402829 1. 什么是OLAP OLAP(On-line Analytical Processing,联机分析处理)是在基于数据仓库 ...

  8. centOS7安装nginx及nginx配置

    安装所需插件1.安装gccgcc是linux下的编译器在此不多做解释,感兴趣的小伙伴可以去查一下相关资料,它可以编译 C,C++,Ada,Object C和Java等语言 命令:查看gcc版本 gcc ...

  9. 即时通讯技术文集(第23期):IM安全相关文章(Part12) [共15篇]

    为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第23 期. [- 1 -] 理论联系实际:一套典型的IM通信协议设计详解(含安全层设计) [链 ...

  10. 痛苦调优10小时,我把 Spark 脚本运行时间从15小时缩短到12分钟!

    周一我就有个困惑,还写成文章了:如何从 Spark 的 DataFrame 中取出具体某一行,里面提了自己猜想的几种解决方案. 没想到这么快就要面对这个问题了,我用小孩子都听得懂的例子描述一下我在干什 ...