java线程教程_【扎实基本功】Java基础教程系列之多线程

1. 多线程的概念

1.1 进程、线程、多进程的概念

进程:正在进行中的程序(直译)。

线程是程序执行的一条路径, 一个进程中可以包含多条线程。

一个应用程序可以理解成就是一个进程。

多线程并发执行可以提高程序的效率, 可以同时完成多项工作。

1.2 多线程应用场景

VNC同时共享屏幕给多个电脑。

迅雷开启多条线程一起下载。

QQ同时和多个人一起视频。

服务器同时处理多个客户端请求。

1.3 并行和并发的区别

并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)。

并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于间时间隔较短,使人感觉两个任务都在运行(画图-任务调度)。

1.jpg

2.jpg

1.4 Java程序运行原理

Java命令会启动java虚拟机(JVM),等于启动了一个应用程序,也就是启动了一个进程。

该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法

一个应用程序有且只有一个主线程,程序员不能New主线程,可以New子线程。

3.jpg

1.5 JVM启动的是多线程吗?

JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

main方法的代码执行的位置就是在主线程(路径)。

一个进程有多个线程。

finalize() 这个方法在子线程(垃圾回收线程)执行。

package day03;

public class Demo01 {

public static void main(String[] args) {

/*JVM的启动是多线程的吗?【面试题】

1.JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

2.main方法的代码执行的位置就是在主线程(路径)

3.一个进程有多个线程

4.finalize()这个方法在子线程(垃圾回收线程)执行*/

System.out.println("AAAAA");

System.out.println("BBBBB");

System.out.println("CCCCC");

System.out.println("DDDDD");

//打印线程名称

System.out.println(Thread.currentThread());//主线程

for (int i = 0; i < 3; i++) {

new Student();

System.gc(); //启动垃圾回收

}

}

}

class Student {

//被垃圾回收器回收时,会调用

//对象从内存释放时,会调用

@Override

protected void finalize() throws Throwable {

// TODO Auto-generated method stub

System.out.println("student 被回收了...");

//打印线程名称

System.out.println(Thread.currentThread());//子线程

}

}

4.jpg

2. Java中线程的实现方式

2.1 方式一: 继承Thread

使用步骤:

定义一个类继承Thread类。

覆盖Thread类中的run方法。

直接创建Thread的子类对象创建线程。

调用start方法开启线程并调用线程的任务run方法执行。

package day03.lesson03;

public class demo0 {

public static void main(String[] args) {

for (int i = 1; i <= 12; i++) {

ThreadDemo threadDemo = new ThreadDemo();

threadDemo.start();

}

}

}

class ThreadDemo extends Thread {

@Override

public void run() {

System.out.println("购买火车票任务……" + Thread.currentThread());

System.out.println("线程名称:" + this.getName());

}

}

5.jpg

注: 不能通过threadDemo.run()的方式来执行任务,因为这种试的任务是在主线程执行的。

正确的执行任务的方式,调用threadDemo.start()方法,内部会开启新线程,调用run方法。

P.S.

可以通过Thread的getName方法获取线程的名称,名称格式:Thread-编号(从0开始)。

Thread在创建的时候,该Thread就已经命名了。源码如下:

6.jpg

JVM创建的主线程的任务都定义在了主函数中。而自定义的线程,它的任务在哪儿呢?

Thread类用于描述线程,线程是需要任务的。所以Thread类也有对任务的描述。这个任务就是通过Thread类中的run方法来体现。也就是说,run方法就是封装自定义线程运行任务的函数,run方法中定义的就是线程要运行的任务代码。

总结:

开启线程是为了运行指定代码,所以只有继承Thread类,并复写run方法,将运行的代码定义在run方法中即可。

2.2 方式二: 实现Runnable接口

使用步骤:

定义类实现Runnable接口。

实现run方法。

把新线程要做的事写在run方法中。

创建自定义的Runnable的子类对象,创建Thread对象传入Runnable。

调用start()开启新线程, 内部会自动调用Runnable的run()方法。

package day03;

public class demo02 {

public static void main(String[] args) {

//1.创建runable对象

TrainTask task = new TrainTask();

//2.创建Thread对象

Thread t1 = new Thread(task);

//3.启动线程

t1.start();

for (int i=1;i<=12;i++){

Thread td = new Thread(task);

td.start();

}

}

}

class TrainTask implements Runnable{

@Override

public void run() {

System.out.println("购买火车票任务……" + Thread.currentThread());

System.out.println("线程名称:" + Thread.currentThread().getName());

}

}

7.jpg

实现Runnable接口的好处:

1. 将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象的思想将任务封装成对象。

2. 避免了Java单继承的局限性。所以,创建线程的第二种方式较为常用。

2.3 两种方式的区别

查看源码的区别:

继承Thread : 由于子类重写了Thread类的run(), 当调用start()时直接找子类的run()方法。

实现Runnable : 构造函数中传入了Runnable的引用, 有个成员变量记住了它, 调用run()方法时内部判断成员变量Runnable的引用是否为空。

9.jpg

继承Thread

好处是: 可以直接使用Thread类中的方法,代码简单。

弊端是: 如果已经有了父类,就不能用这种方法。

实现Runnable接口

好处是: 即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,代码更灵活。

弊端是: 不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂。

8.jpg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值