多线程概述:
进程:正在运行中的程序。
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程的定义:(程序中的控制单元,或称执行路径)
就是进程中一个独立的控制单元,线程在控制着进程的执行。
一个进程中至少有一个线程。
多个程序同时在执行,CPU在执行着快速的切换。
多线程存在的意义:
Java虚拟机的介绍:
JAVA VM启动的时候会有一个java.exe。
该进程中至少有一个线程负责Java程序的执行,
而且这个线程运行的代码存在于main方法中。
该线程称之为主线程。
拓展:其实更细节说明JVM,JVM启动不只一个线程,还有垃圾回收机制的线程。
多线程的特征:
多线程的创建方式:
一、继承Thread类;
1.子类覆盖父类中的run方法,将线程运行的代码存放在run中;
2.建立子类对象的同时线程也被创建;
3.通过调用start方法开启线程。
二、
1.自定义线程。
Java.lang thread包
通过对API的查找,Java已经提供了线程对这类事物的描述,就是thread类。
创建线程的第一种方法:继承thread类;
步骤:
1.定义类继承thread;
2.复写thread类中的run方法;
目的:将自定义代码存储在run方法。让线程运行。
3.调用线程的start方法。
该方法有两个作用:启动线程,调用run方法;
可以发现,运行结果每一次都不同。
因为多个线程都获取CPU的执行权,CPU执行到谁,谁就执行;
明确一点,在执行的某一时刻,只能有一个程序在运行,(多核
CPU在做着快速的切换,以达到看上去是同时运行的效果。
我们可以形象的把多线程的运行为行为在互相抢占CPU的执行权
这就是多线程的一个特性:随机性。谁抢到谁就执行,至于执行多长时间,由CPU决定。
Class Demo extends thread
{
public void run()
{
For(int i=0;i<100;i++)
System.out.println(“demo run “);
}
}
Class threadDemo
{
Public static void main(String [] args)
{
Demo d=new Demo();
.start(); // 开启线程并执行该线程的run方法。
d.run(); // 仅仅是对象调用方法。而线程创建了,并没有运行。
For(int x=0;x<60;x++)
System.out.println(“hello world--”+x);
Thread t=new Thread();
}
}
Run方法和start方法的特点:
为什么要覆盖run方法呢?
Thread类用于描述线程。
该类就定义一个功能,用于存储线程要运行的代码。该存储功能就是run方法。
也就是说Thread类中的run方法,用于存储线程要运行的代码。
第二种方法:实现Runnable接口
1.定义类实现Runnable接口;
2.覆盖Runable接口中的run方法;
将线程要运行的代码存放在该run方法中;
3.通过Thread类建立线程对象。
4.将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
为什么要将Runable接口的子类对象传递Thread的构造函数。
因为,自定义的run方法所属的对象时Runnable接口的子类对象。
所以要让线程去指定对象的run方法。就必须明确该run方法所属对象。
5.调用Thread类的start方法开启线程并用Runnable接口子类的run方法。
实现Runnable方法和继承Thread类方法有什么区别?
实现Runnable方式的好处:避免了单继承的局限性;
在定义线程时,建立使用实现方式。
代码的存放位置不同:
继承Thread类:线程代码存放Thread子类run方法中;
实现Runnable:线程代码存放在接口子类的run方法中。
先举个实例
/*需求:简单的售票程序
多个窗口同时售票
*/
多线程的状态流程:
多线程的安全问题
问题的原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行一部分,还没有执行完。
另外一个线程参与进来执行,导致共享数据的错误。
解决方法:
对多线程操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其它线程不可以参与执行。
JAVA对于多线程的安全问题提供了专业的解决方式。
就是同步代码块。
Synchronized(对象)
{
需要被同步的代码
}