进程

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

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

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. Think in Java之构造器的真正调用顺序

    构造器是OOP的重要组成部分,很多人认为它很容易.只不过是new了一个对象而已.而think in java的作者却告诉我们,其实这并不容易.先看下面这个例子.在你没看结果之前,你觉得你的答案是对的么 ...

  2. 2013年ImportNew最受欢迎的10篇文章

    2013年即将过去,提前祝大家元旦快乐,ImportNew 整理出了本年度最受欢迎的前10篇Java和Android技术文章,每篇文章仅添加了摘要.如果您是我们的新访客,那下面这些文章不能错过.如果您 ...

  3. [天坑]之qrcode二维码在app内置浏览器中无法显示问题

    记录一下最近的工作难点,之一... 首先本项目使用的是qrcode-generator,市面上生成二维码的第三方库有很多qrcode.vue.qrcode.QRious等等 <div id=&q ...

  4. 19号CSS学习

    一.CSS的复合选择器 更高效的选择目标元素. 后代选择器.子选择器.并集选择器.伪类选择器等. 1.后代选择器 可以选择父元素里的子元素. 又称包含选择器. 必须是空格,必须是后代,ul li {c ...

  5. MySQL8设置root用户远程访问

    查询当前root状态,默认root的host是localhost use mysql; select user,host from user; update root的host为% update us ...

  6. 【Amadeus原创】IPAD忘记密码重置恢复出厂设置

    打开iTunes,确保您的 iPad 没有连接到电脑. 按住顶部按钮,直到出现关机滑块.拖移这个滑块以将 iPad 关机. 在按住主屏幕按钮的同时,将 iPad 连接到电脑.继续按住主屏幕按钮,直到看 ...

  7. 【软件配置】使用 brew 安装特定版本软件

    目录 使用 brew 安装特定版本软件 背景 方法一:直接安装 方法二:利用历史的 rb 文件安装 参考资料 使用 brew 安装特定版本软件 背景 brew 是 Mac 下非常好用的包管理工具,可以 ...

  8. 百度地图各种控件:地图平移缩放控件NavigationControl、地图类型控件MapTypeControl

    注:代码复制即可用,标色代码为主要代码 百度地图提供了如下控件: 1.Control:控件的抽象基类,所有控件均继承此类的方法.属性.通过此类您可实现自定义控件. 2.NavigationContro ...

  9. 【SpringMVC】获取请求参数的方式

    SpringMVC获取请求参数的方式 目录 SpringMVC获取请求参数的方式 方式1:ServletAPI 方法2:通过控制器方法的形参获取请求参数 方法3:@RequestParam 方法4:@ ...

  10. SpringBoot重点详解--使用Actuator进行健康监控

    目录 添加依赖与配置 Actuator监控项 Actuator监控管理 打开或关闭 端口与地址 Actuator是Springboot提供的用来对应用系统进行自省和监控的功能模块,借助于Actuato ...