多线程(一)
来源:互联网 发布:csgo国服mac 编辑:程序博客网 时间:2024/06/05 06:20
进程和线程的概述
- 进程就是应用程序在内存中分配的空间,也可理解为一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序就是一个执行路径或者叫一个控制单元。
- 线程就是进程中负责程序执行的执行单元,也可理解为进程中的一个独立的控制单元。线程在控制着进程的执行。
多线程
多线程的概述
一个进程中至少有一个线程在负责该进程的运行。如果一个进程中出现了多个线程,就称该程序为多线程程序。
多线程解决的问题
多线程这门技术的出现解决了多部分代码同时执行的需求,这样做的好处就是可以提高用户的体验效果。
这里有一个疑问——多线程真的能提高效率吗?显然不是,反倒容易死机,但可合理的使用CPU资源。
JVM中的多线程与垃圾回收
多线程的运行是根据CPU的切换完成的,怎么切换CPU说了算,所以多线程运行有一个随机性(CPU的快速切换造成的)。
本节我首先给出结论——JVM中的多线程至少有两个线程:
- 一个是负责自定义代码运行的,这个从main方法开始执行的线程称之为主线程。
- 一个是负责垃圾回收的。
然后我通过一个简单的案例来演示JVM中的多线程。例如,有如下实验代码:
class Demo{ // 定义垃圾回收方法 public void finalize() { System.out.println("demo ok"); }}class FinalizeDemo { public static void main(String[] args) { new Demo(); new Demo(); new Demo(); System.gc(); // 启动垃圾回收器。 System.out.println("Hello World!"); }}
运行FinalizeDemo类,可能在屏幕上打印(截图如下):
通过实验会发现每次的结果不一定相同,那是因为随机性造成的。而且每一个线程都有自己的代码内容,这个称之为线程的任务,之所以创建一个线程就是为了去运行指定的任务代码。而线程的任务都封装在特定的区域中,比如:
- 主线程运行的任务都定义在main方法中。
- 垃圾回收线程在收垃圾时都会运行finalize方法。
创建线程方式一
如何在自定义的代码中,自定义一个线程呢?也即如何建立一个执行路径呢?
答:通过对API的查找,java已经提供了对线程这类事物的描述,即Thread
类。该类的描述中创建线程有两种方式,下面我就来讲解其第一种方式。
创建线程的第一种方式:继承Thread
类。
步骤:
- 继承
Thread
类 - 重写
Thread
类中的run()
。目的:将自定义的代码存储在run()
,让线程运行 - 创建子类对象也即创建线程对象
- 调用线程的
start()
。该方法有2个作用:启动线程,调用run()
例,
class Demo extends Thread { public void run() { for (int x = 0; x < 60; x++) { System.out.println("demo run---"+x); } }}class ThreadDemo { public static void main(String[] args) { Demo d = new Demo(); // 创建好一个线程 // d.start(); // 开启线程,并执行该线程的run() d.run(); // 仅仅是对象的调用方法,而线程创建了,并没有被运行 for (int x = 0; x < 60; x++) { System.out.println("Hello World!---"+x); } }}
发现运行结果每一次都不同。
因为多个线程都在获取CPU的执行权,CPU执行到谁,谁就运行。明确一点,在某一个时刻,只能有一个程序在运行(多核除外)。CPU在做着快速的切换,以达到看上去是同时运行的效果。我们可以形象地把多线程的运行形容为互相抢夺CPU的执行权,这就是多线程的一个特点:随机性。谁抢到谁执行,至于执行多长,CPU说了算。
问题一、为什么要覆盖run()呢?
答:Thread
类用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run()
。也就是说Thread
类中的run()
用于存储线程要运行的代码。
问题二、调用start方法和调用run方法的区别?
答:调用start方法会开启线程,让开启的线程去执行run方法中的线程任务;而直接调用run方法,线程并未开启,去执行run方法的只有主线程。
练习:创建两个线程,和主线程交替执行。
解:
class Test extends Thread { Test(String name) { super(name); } public void run() { for (int x = 0; x < 60; x++) { System.out.println((Thread.currentThread()==this)+"..."+this.getName()+" run..."+x); } }}class ThreadTest { public static void main(String[] args) { Test t1 = new Test("one---"); Test t2 = new Test("two+++"); t1.start(); t2.start(); for (int x = 0; x < 60; x++) { System.out.println("main..."+x); } }}
通过上例,可发现原来线程都有自己默认的名称:Thread-编号
,该编号从0开始。
static Thread currentThread()
:获取当前线程对象getName()
:获取线程名称setName()或者构造函数
:设置线程名称
多线程的运行状态
多线程的运行状态用图来表示即为:
创建线程方式二
以此例引申出创建线程的第二种方式:
例,需求:简单的卖票程序。多个窗口同时卖票。
class Ticket implements Runnable { private int tick = 100; public void run() { while(true) { if(tick > 0) { try { Thread.sleep(10); } catch(Exception e) {} System.out.println(Thread.currentThread().getName()+"...sale:"+tick--); } } }}class TicketDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t); // 创建一个线程 Thread t2 = new Thread(t); // 创建一个线程 Thread t3 = new Thread(t); // 创建一个线程 Thread t4 = new Thread(t); // 创建一个线程 t1.start(); t2.start(); t3.start(); t4.start(); }}
创建线程的第二种方式:实现Runnable
接口。
步骤:
- 定义类实现
Runnable
接口 - 覆盖
Runnable
接口中的run()
。目的:将线程要运行的代码存放在该run()
中 - 通过
Thread
类建立线程对象 - 将
Runnable
接口的子类对象作为实际参数传递给Thread
类的构造函数。
为什么要将Runnable
接口的子类对象作为实际参数传递给Thread
类的构造函数?
答:因为自定义的run()
所属的对象是Runnable
接口的子类对象,所以要让线程去运行指定对象的run()
,就必须明确该run()
所属的对象。 - 调用
Thread
类的start()
开启线程并调用Runnable
接口子类的run
方法。
实现Runnable接口的好处
现将实现Runnable接口的好处总结如下:
- 避免了继承Thread类的单继承的局限性。
- Runnable接口的出现更符合面向对象,将线程任务单独进行了对象的封装。
- Runnable接口的出现降低了线程任务和线程对象的耦合性。
所以,以后创建线程都使用第二种方式。
- 【多线程】(一)创建多线程
- 多线程(一)
- 多线程一
- 多线程一
- 多线程(一)
- 多线程一
- 多线程(一)
- 多线程一
- 多线程一
- 多线程一
- 多线程(一)
- 多线程(一)
- 多线程(一)
- 多线程一
- Java多线程(一) 认识多线程
- java多线程:多线程(一)
- 多线程(一):初识多线程
- 多线程(一)多线程基础、多线程状态
- 洛谷10月月赛R1-T2-一道简单题 Sequence2
- Codeforce Round #439 A B C 题解
- 关于PLSQL日期时间设置的问题
- contentDocument实现iframe自适应子页面高度
- 两端对齐文本效果
- 多线程(一)
- JAVA正则表达式使用总结
- 四、ESP8266之 TCP客户端 (基于LUA开发)
- CentOS7 部署LDAP服务器
- 调试器
- spingboot 显示jsp页面
- Quartz-Trigger详解
- 微信和支付宝APP支付使用总结
- 一个Filter配置多个url-pattern