38. [Java]多线程
38.1. 创建
使用Thread类开发多线程程序的步骤:
自定义一个子类,继承Thread
在子类中,重写run()方法(run方法中书写的是线程要执行的任务代码)
Thread类中包含了创建并执行多线程的功能方法+线程要执行的任务(耦合度过高)创建一个子类对象
通过子类对象调用.start() 开启一个新线程并执行
使用Runnable接口开发多线程的步骤:
自定义一个实现Runnable接口的子类
在子类重写run方法
创建一个子类对象,并把该对象作为参数传递给Thread对象
创建一个Thread对象,并把实现Runnable接口的子类对象作为参数
调用Thread对象中的start方法
使用Runnable接口比Thread类的优点:
适合多个程序实现共享同一份资源
实现了解耦
避免Java中的单继承
实现Callable接口来创建线程:
自定义一个子类实现Callable
在子类中重写call方法
创建线程池
创建Callable子类对象
把Callable对象作为参数传递给线程池
38.2. 线程安全
发生原因:
安全问题都是由全局变量及静态变量造成的
多个线程同时对一个共享数据进行访问(在访问的同时存在修改操作),由于CPU切换不同的线程可能存在: A线程进行了修改,B线程却使用了修改前的数据
解决方案:
本质:把多线程变成单线程
引入线程同步机制
同步代码块
针对run方法中的代码,使用synchronized关键字,把部分代码添加同步机制
同步机制:在同一个而时间,只能有一个线程执行
原理:线程在执行之前先获取到一个锁,然后开始执行线程任务,只有拿到锁的线程执行完包含在synchronized代码块中的内容之后,才会释放锁,才可以让其他线程拿到这个锁
同步机制,关键是实现利用:锁(对象锁)
锁: 对象锁。任何对象都可以当锁使用
String lock = new String()
Object lock = new Object()
同步方法
针对方法进行同步,同步方法只能用在方法上
格式:public synchronized void method(){…}
同步方法中的锁:
非静态方法:锁是this(锁,当前对象)
静态方法:静态方法没有对象的概念。所示Class(锁,类名.class)
锁机制
38.3. 线程的生命周期
从线程的创建开始,一直到线程的销毁,整个过程称为:生命周期
划分:
创建 start() 线程创建成功
就绪
运行
死亡
38.4. 线程控制
控制方法:
sleep() 当前执行的线程进入睡眠状态
join() 等待当前线程死亡,当前线程必须执行完才能执行其他线程
setDeamon() 设置当前线程为和守护线程,特点:当没有普通线程在执行时,守护线程也停止运行