【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. }


相关文章
|
2天前
|
Java
Java中,有两种主要的方式来创建和管理线程:`Thread`类和`Runnable`接口。
【6月更文挑战第24天】Java创建线程有两种方式:`Thread`类和`Runnable`接口。`Thread`直接继承受限于单继承,适合简单情况;`Runnable`实现接口可多继承,利于资源共享和任务复用。推荐使用`Runnable`以提高灵活性。启动线程需调用`start()`,`Thread`直接启动,`Runnable`需通过`Thread`实例启动。根据项目需求选择适当方式。
12 2
|
7天前
|
Java C++ 开发者
线程创建的终极对决:Thread 类 VS Runnable 接口,你站哪边?
【6月更文挑战第19天】在Java多线程编程中,通过`Thread`类直接继承或实现`Runnable`接口创建线程各有优劣。`Thread`方式简洁但不灵活,受限于Java单继承;`Runnable`更灵活,适合资源共享和多接口实现,提高代码可维护性。选择取决于项目需求和设计原则,需权衡利弊。
|
2天前
|
API C++
c++进阶篇——初窥多线程(三)cpp中的线程类
C++11引入了`std::thread`,提供对并发编程的支持,简化多线程创建并增强可移植性。`std::thread`的构造函数包括默认构造、移动构造及模板构造(支持函数、lambda和对象)。`thread::get_id()`获取线程ID,`join()`确保线程执行完成,`detach()`使线程独立,`joinable()`检查线程状态,`operator=`仅支持移动赋值。`thread::hardware_concurrency()`返回CPU核心数,可用于高效线程分配。
|
6天前
|
安全 测试技术
如何在匿名thread子类中保证线程安全
如何在匿名thread子类中保证线程安全
|
7天前
|
Java
揭秘!为何Java多线程中,继承Thread不如实现Runnable?
【6月更文挑战第19天】在Java多线程中,实现`Runnable`比继承`Thread`更佳,因Java单继承限制,`Runnable`可实现接口复用,便于线程池管理,并分离任务与线程,提高灵活性。当需要创建线程或考虑代码复用时,实现`Runnable`是更好的选择。
|
4天前
|
存储 Linux C语言
c++进阶篇——初窥多线程(二) 基于C语言实现的多线程编写
本文介绍了C++中使用C语言的pthread库实现多线程编程。`pthread_create`用于创建新线程,`pthread_self`返回当前线程ID。示例展示了如何创建线程并打印线程ID,强调了线程同步的重要性,如使用`sleep`防止主线程提前结束导致子线程未执行完。`pthread_exit`用于线程退出,`pthread_join`用来等待并回收子线程,`pthread_detach`则分离线程。文中还提到了线程取消功能,通过`pthread_cancel`实现。这些基本操作是理解和使用C/C++多线程的关键。
|
7天前
|
安全 Java
【极客档案】Java 线程:解锁生命周期的秘密,成为多线程世界的主宰者!
【6月更文挑战第19天】Java多线程编程中,掌握线程生命周期是关键。创建线程可通过继承`Thread`或实现`Runnable`,调用`start()`使线程进入就绪状态。利用`synchronized`保证线程安全,处理阻塞状态,注意资源管理,如使用线程池优化。通过实践与总结,成为多线程编程的专家。
|
7天前
|
Java 开发者
告别单线程时代!Java 多线程入门:选继承 Thread 还是 Runnable?
【6月更文挑战第19天】在Java中,面对多任务需求时,开发者可以选择继承`Thread`或实现`Runnable`接口来创建线程。`Thread`继承直接但限制了单继承,而`Runnable`接口提供多实现的灵活性和资源共享。多线程能提升CPU利用率,适用于并发处理和提高响应速度,如在网络服务器中并发处理请求,增强程序性能。不论是选择哪种方式,都是迈向高效编程的重要一步。
|
7天前
|
Java 开发者
震惊!Java多线程的惊天秘密:你真的会创建线程吗?
【6月更文挑战第19天】Java多线程创建有两种主要方式:继承Thread类和实现Runnable接口。继承Thread限制了多重继承,适合简单场景;实现Runnable接口更灵活,可与其它继承结合,是更常见选择。了解其差异对于高效、健壮的多线程编程至关重要。
|
8天前
|
Java 程序员
Java多线程编程是指在一个进程中创建并运行多个线程,每个线程执行不同的任务,并行地工作,以达到提高效率的目的
【6月更文挑战第18天】Java多线程提升效率,通过synchronized关键字、Lock接口和原子变量实现同步互斥。synchronized控制共享资源访问,基于对象内置锁。Lock接口提供更灵活的锁管理,需手动解锁。原子变量类(如AtomicInteger)支持无锁的原子操作,减少性能影响。
18 3