Java多线程
- 1.进程:是一个正在执行中的程序
每一个进程执行都有一个执行顺序,该顺序是一个执行路劲,或者叫做一个控制单元 - 2.线程:是进程中一个独立的控制单元线程在控制着进程的执行一个进程中至少有一个线程
****JVM启动的时候会有一个进程java.exe.
该进程中至少有一个线程负责java程序的执行
而且这个进程运行的代码存在于main方法中
该线程称之为主线程** - 3.扩展:其实更细节地说明jvm,jvm启动不止一个线程,还有一个垃圾回收机制的线程
创建线程的第一种方式,继承Thread类
步骤:
* 1.创建一个类,让它继承Thread类
* 2.重写该类的run方法
为什么要重写run方法:Thread类用于描述一个线程,该类定义了一个功能,用来存储线程要运行的代码,该存储功能的实现就依靠run方法
* 3.调用线程的start方法(该方法有两个作用—>启动线程,调用run方法)
实现线程的第二种方式:实现Runnable接口fan
步骤:
* 1.定义实现Runnable接口;
* 2.覆盖Runnable接口中的run方法
将线程要运行的代码存放到run方法中
* 3.通过Thread类创建线程对象
* 4.将runable接口的对象作为实际参数传给 Thread类的构造函数
为什么要将Runnable接口的子类对象传给Thread的构造函数因为,自定义的run方法是属于Runnable子类对象所以要让线程去执行指定对象的run方法,就必须明确该run方法的所属对象
* 5.调用Thread类的start方法 开启线程并调用Runnable子类的run方法
接口的实现方式和继承方式有什么区别呢?
- 实现方式的好处: 实现方式避免了单继承的局限性(在定义线程时,建议使用实现方式)
- 两种方式的区别
1.继承 Thread类,运行代码存放在Thread子类的run方法中
2.实现Runnable,运行代码存放在接口子类的run方法中
多线程运行过程中,很容易出现安全问题
- 出现问题的原因:当多条语句在操作同一个线程的共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误
- 解决的办法:对多条操作共享数据的语句,只能让一个线程都执行完,其它线程不能参与执行
- Java对于多线程的安全问题提供了专业的解决办法—->同步代码块
同步代码块格式(经典案例—火车上的卫生间)
同步的两种表现形式
* 同步代码块
* 同步函数(在函数前加上synchronized关键)他的锁是this–>当前对象.
如果同步函数被static修饰,他的锁就不是this了,因为静态方法中也不可以定义this;他的锁是该方法所在类对应的字节码文件对象(存在于内存当中)
* 字节码文件对象–类名.class–该类的类型为Class同步的前提:
* 1.必须要有两个或者两个以上的线程
* 2.必须是多个线程使用同一个锁
必须保证同步中只能有一个线程在运行
同步代码块的好处和弊端
- 好处:解决了多线程的线程安全问题
- 弊端:多个线程都需要判断锁,消耗了资源
synchronized(对象){
(其中对象可以为任意对象,该对象如同锁,持有锁的线程可以在同步中执行)没有持有锁的线程,即使获取了cpu的执行权,也进不去,因为没有锁
需要被同步的代码
}
下边是一个例子:
class Ticket implements Runnable{
private int tick=100;//总共的票数
Object object=new Object();
public void run(){
while(true){
synchronized (object){
if(tick>0){
try {
Thread.sleep(10);
}catch(Exception e){
e.printStackTrace();
}//运行后发现,出现了0,-1,-2等错票,多线程出现了安全问题
System.out.println(Thread.currentThread().getName()+"sale:"+tick--);
}
}
}
}
}
public class ThreadLianXi {
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();
/*Ticket ticket1=new Ticket();
Ticket ticket2=new Ticket();
Ticket ticket3=new Ticket();
Ticket ticket4=new Ticket();
ticket1.start();
ticket2.start();
ticket3.start();
ticket4.start();*/
}
多线程中安全问题的寻找
1.明确哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中哪些语句是用来操作共享数据的