【JavaEE】认识线程&Thread类及常用方法&线程状态(一)

简介: 【JavaEE】认识线程&Thread类及常用方法&线程状态

一:认识线程:

每一个线程就是一个“执行流”。每个线程之间都可以按照顺序执行自己的代码,多个线程之间可以同时执行自己的代码。比如我们之前一直写的程序都只是在main线程中写的代码,以前写的代码都是单个线程的。

那么为什么会出现线程?主要有2个原因:

1)并发编程的需要

单核CPU的发展已经到了瓶颈,现在已经到了多核CPU的时代,而并发编程可以让CPU的资源得到充分的利用。

2)进程太“重”了。

虽然进程也可以实现并发编程,但是进程还是太“重”了。

进程在创建时开销非常大

进程在销毁是开销非常大

进程在调度的时候也开销非常大!

我们这里所说的“重”指的是“资源分配/回收”。

二、线程的优点:

所以我们的线程就应运而生。相对于进程而言。线程就更加的“轻量化”了,所以线程也被称为“轻量化进程”。这里说的轻量是因为线程在创建、销毁和调度的时候的开销都要比进程低。而线程之所以开销低的原因又在于线程省去了一些“申请资源和释放资源的步骤”。

比如这样的一个例子:

小明家开了一个工厂来生产冰箱,经过了一段时间的经营,发现生产的冰箱非常的受欢迎,销量很高,于是小明想到了两种方案来提高生产力:

方案一(多进程方案):再寻找一个工业场地,购进一批同样的机器来进行生产。

方案二(多线程方案):把原工厂的地方拾掇拾掇,腾出一块地方,购进一批新的机器放机器进行生产

显然我们可以看出,第二种方案(多线程)的开销要明显低于第一种方案(多进程)。因为第二种方案没有进行更大的资源开销,而是在原工厂的基础上进行了复用,也就是还是利用了原场地。这样下来的开销就大大减少了。

三、进程和线程的区别(面试题):

1.、进程包含线程。一个进程中可以有一个线程,也可以有多个线程。

2、进程和线程都可以解决并发编程问题,但是进程在频繁的创建和销毁的时候开销更大,线程更小。(线程比进程更加的轻量)

3、进程是操作系统资源分配的基本单位,线程是操作系统进行调度的基本单位。

4、进程与进程之间不共享内存空间,同一个进程中的线程共享内存空间。(这就可能会出现一个线程崩了,别的也会收到影响,而进程之间不会影响。也就是说进程比线程更安全)

四、第一个多线程程序:

线程是操作系统里面的概念,Java标准库中的Thread类可以视为是对操作系统提供的API进行了抽象和封装。

通过第一个多线程的程序感受一下多线程和单一线程的区别。

1. package Thread;
2. 
3. class myThread extends Thread{
4. //使用一个boolean类型进行判断,让该线程只打印100次
5. private boolean flag=true;
6. private int count=1;
7. @Override
8. public void run() {
9. 
10. while(flag){
11. if(count==100){
12.                 flag=false;
13.             }
14. try {
15.                 Thread.sleep(1000);
16.             } catch (InterruptedException e) {
17. throw new RuntimeException(e);
18.             }
19.             System.out.println("hello Thread");
20.             count++;
21.         }
22. 
23.     }
24. }
25. public class ThreadDemo2 {
26. public static void main(String[] args) throws InterruptedException {
27.         Thread t=new myThread();
28.         t.start();
29. //主线程打印50次
30. for (int i = 0; i <50 ; i++) {
31.             Thread.sleep(500);
32.             System.out.println("hello main");
33.         }
34. 
35. 
36.     }
37. }

该程序并没有先执行其中一个线程,在执行另一个的线程,这就是多线程的魅力所在。  

我们从上述结果中也可以看到一个现象就是main线程和t线程谁先执行是不确定的,是完全由我们的系统自己决定的。所以线程的调度是“抢占式执行,随机调度”

五、创建线程的方式

我们创建线程可以有五种方式:

1、创建子类继承Thread类,重写run方法。

1. package Thread;
2. 
3. class myThread1 extends Thread{
4. @Override
5. public void run() {
6.         System.out.println("hello Thread");
7.     }
8. }
9. public class ThreadDemo3 {
10. public static void main(String[] args) {
11.         Thread t1=new myThread1();
12.         t1.start();
13.     }
14. }

run方法描述了该线程要执行的任务内容,即要执行的代码,而调用start方法才是真正创建了线程,才会执行任务。

2、实现Runnable接口,重写run方法。

1. package Thread;
2. 
3. class myRunnable implements Runnable{
4. 
5. @Override
6. public void run() {
7.         System.out.println("hello Thread");
8.     }
9. }
10. public class ThreadDemo4 {
11. public static void main(String[] args) {
12.         myRunnable runnable=new myRunnable();
13.         Thread t=new Thread(runnable);
14.         t.start();
15. 
16.     }
17. }

这个方法是通过实现Runnable接口,创建出一个Runnable的实例,把这个实例传给Thread对象,通过这个实例来描述要执行的任务。

3、匿名内部类创建Thread子类对象。

1. package Thread;
2. 
3. public class ThreadDemo5 {
4. public static void main(String[] args) {
5.         Thread t=new Thread(){
6. @Override
7. public void run() {
8.                 System.out.println("hello Thread");
9.             }
10.         };
11. 
12.         t.start();
13. 
14.     }
15. }

4、匿名内部类创建Runnable子类对象

1. package Thread;
2. 
3. public class ThreadDemo6 {
4. public static void main(String[] args) {
5. Thread t = new Thread(new Runnable() {
6. @Override
7. public void run() {
8.                 System.out.println("hello Thread");
9.             }
10.         });
11.         t.start();
12.     }
13. }

5、使用lambda表达式(最推荐写法)

1. package Thread;
2. 
3. public class ThreadDemo7 {
4. public static void main(String[] args) {
5.         Thread t=new Thread(()->{
6.             System.out.println("hello Thread");
7.         });
8.         t.start();
9.     }
10. }


相关文章
|
29天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
2月前
|
算法 安全 Java
三种方法教你实现多线程交替打印ABC,干货满满!
本文介绍了多线程编程中的经典问题——多线程交替打印ABC。通过三种方法实现:使用`wait()`和`notify()`、`ReentrantLock`与`Condition`、以及`Semaphore`。每种方法详细讲解了实现步骤和代码示例,帮助读者理解和掌握线程间的同步与互斥,有效解决并发问题。适合不同层次的开发者学习参考。
44 11
|
1月前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
53 3
|
2月前
|
安全 Java 调度
|
2月前
|
安全 Java 程序员
线程安全与 Vector 类的分析
【8月更文挑战第22天】
24 4
|
2月前
|
安全 Java API
|
2月前
|
安全 Java API
Java多线程编程:使用Atomic类实现原子操作
在Java多线程环境中,共享资源的并发访问可能导致数据不一致。传统的同步机制如`synchronized`关键字或显式锁虽能保障数据一致性,但在高并发场景下可能导致线程阻塞和性能下降。为此,Java提供了`java.util.concurrent.atomic`包下的原子类,利用底层硬件的原子操作确保变量更新的原子性,实现无锁线程安全。
15 0
【多线程面试题 二】、 说说Thread类的常用方法
Thread类的常用方法包括构造方法(如Thread()、Thread(Runnable target)等)、静态方法(如currentThread()、sleep(long millis)、yield()等)和实例方法(如getId()、getName()、interrupt()、join()等),用于线程的创建、控制和管理。
|
2月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
64 1
|
4天前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口