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


相关文章
|
1月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
26 3
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
22 2
|
2月前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
46 2
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
35 2
|
2月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
24 1
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
55 1
C++ 多线程之初识多线程
|
2月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
41 1
|
2月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
45 1
|
2月前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
29 1