线程的实现方式和线程安全的解决方式
为什么多线程打印是随机的
CPU执行哪个线程是随机的, 不能人为干预
Java线程调度是抢占式的, 多个线程互相抢夺CPU的执行权
CPU高速随机切换 (本质) 线程抢夺CPU资源
线程执行的方式:
第一种方式:继承Tread类
定义类继承Thread类
重写run()方法,要执行的任务
创建子类的对象,调用start()方法启动线程
java.lang.Thread类: 表示线程. 实现了Runnable接口
Thread(): 创建Thead对象
Thread(String threadName): 创建Thead对象并指定线程名
Thread(Runnable target): 通过Runnable对象创建Thread对象
Thread(Runnable target, String threadName): 通过Runnable对象创建对象并指定线程名
void run(): 用于让子类重写, 表示该线程要执行的任务.不能直接调用
void start(): 启动线程, 即让线程开始执行run()方法中的代码
String getName(): 获取线程的名称
void setName(String name): 设置线程名称
//静态方法
static Thread currentThread(): 返回对当前正在执行的线程对象的引用
static void sleep(long millis): 让所在线程睡眠指定的毫秒
Thread常用方法:
java.lang.Thread类: 表示线程. 实现了Runnable接口
Thread(String threadName): 创建Thead对象并指定线程名
void setName(String name): 设置线程名称
使用第二种方式创建线程
定义类: RunnableImpl, 实现Runnable接口
实现Runnable的好处:
- 避免单继承的局限性
- 增强了程序的扩展性, 降低了程序的耦合性(解耦)
线程是Thread, 任务是Runnable实现类对象. 相当于将线程和任务分离
耦合性: 相互之间的关系的紧密程度
耦合性高: 相互之间的关系非常紧密
耦合性低: 相互之间的关系不太紧密
我们追求 "低耦合"
问题发生的场景:多个线程操作共享资源
问题发生的原因:
JVM是抢占式调度, CPU在每个线程之间切换是随机的, 代码执行到什么位置是不确定的
在操作共享资源时, 由于一个线程还没有执行完, 另一个线程就来操作, 就会出现问题 如何解决: 在操作共享资源时, 让线程一个一个来执行, 不要并发操作共享变量, 就可以解决问题
解决线程安全问题的方式:
同步代码块: 使用 synchronized 关键字修饰的代码块, 并传入一个当作锁的对象
synchronized (锁对象) {
// 操作共享数据的代码
}
注意:
锁对象可以是"任意类型的一个对象"
锁对象必须是"被多个线程共享的唯一的"对象
锁对象的作用: 只让一个线程在同步代码块中执行
锁对象, 也称为"同步锁", "对象锁", "对象监视器"
同步的原理:
线程进入同步代码块前, 会"争夺锁对象", "只有一个线程"会抢到锁对象
进入同步代码块的线程, 会"持有锁对象", 并执行同步代码块中的代码
此时同步代码块外的线程, 处于"阻塞"状态, 只能等待
当同步代码块内的线程执行完代码块, 会离开同步代码块, 并"归还锁对象"给同步代码块
等在同步代码块外的其他线程就可以继续争夺锁对象
同步方法: 使用 synchronized 关键字修饰的方法, 具有默认的锁对象
//非静态方法的同步方法
public synchronized void method(){
非静态同步方法的锁对象: this
//静态方法的同步方法
public static synchronized void method(){
静态同步方法的锁对象: 当前类的字节码对象 Class对象
Lock锁
java.util.concurrent.locks.ReentrantLock类: Lock的实现类
void lock(): 获取锁
void unlock(): 释放锁
Lock lock = new ReentrantLock();//成员变量
public void run() {
lock.lock();
try {
//操作共享变量的代码
}finally{
//在finally中保证释放锁
lock.unlock();
Object类中关于线程的方法:
java.lang.Object类:
void notify(): 随机唤醒在同一个锁对象上的某一个处于等待状态的线程
void notifyAll(): 唤醒所有在同一个锁对象上处于等待状态的线程
void wait(): 让当前线程处于"无限等待"状态
void wait(long timeout): 让当前线程处于"计时等待"状态, 时间到或被唤醒后结束此状态
void wait(long timeout, int nanos): 让当前线程处于计时等待状态, 时间到或被唤醒后结束此状态
|
|