多线程

多线程

一个进程是程序运行的实例

线程是一个进程中的执行场景/执行单元

一个进程可以启动多个线程

每个java程序都至少启动了两个线程:main主线程和垃圾回收线程

在不同线程间 堆和方法区共享,但是一个线程一个栈

在多线程的环境中,当main 方法结束只是意味着主栈空了,但是其他的分支线程拥有的支栈还在压栈弹栈。

实现多线程的方法

实现多线程的方法有:

  1. 编写一个类,继承java.langThread类,重写run方法

    start 方法,开辟一个新的栈空间,线程启动成功。启动成功的线程自动调用run方法。run在分支栈的底部,main在主栈的底部,run,main平级。

    直接调用run方法,不会分配一个分支栈。

  2. 创建类,实现Runnable接口,然后使用Thread类将实现了Runnable的类实例传入创建线程对象

线程状态

  1. 新建状态 线程创建即为该状态
  2. 就绪状态 在调用start方法以后,等待系统调度。也就是这个状态
  3. 运行状态 当线程在就绪状态抢夺到时间片,运行run方法就进入运行状态。当时间片用完再次进入就绪状态,抢夺到时间片以后继续运行。
    1. 阻塞状态 当线程遇到阻塞事件,阻塞线程会放弃占有时间片。
    2. 阻塞状态解除 当阻塞状态结束,将进入就绪状态,继续抢夺时间片
  4. 死亡状态 run方法执行结束

常用方法

setName 修改线程名字

getName 获取线程名字

currentThread 获取当前线程对象(静态方法)

sleep 让当前线程进入休眠状态指定时间(静态方法)

interrupt 唤醒休眠线程 该唤醒机制,依靠了java的异常机制,java会抛出一个睡眠被强制打断的异常

stop 强行杀死线程,容易丢数据

run方法中的异常只能try catch,不能抛出,因为父类Thread的run方法并没有抛出异常

线程调度模型

分为两种:

  1. 抢占式 按照线程优先级分配时间片

  2. 均分式 平均分配时间片,每个线程占用的cpu时间片时间长度相同

java采用的是抢占式线程调度模型

SetPriority 修改线程优先级

GetPriority 获取线程优先级

yield (静态方法)使当前线程让位,即从运行状态立即进入就绪状态

join 合并线程。被合并的线程将在当前线程中阻塞方式运行

线程安全

数据在多线程并发的环境下是否安全。

当多线程并发修改共享数据时就会存在线程安全问题。

解决方案,使用线程同步机制。

线程同步机制

synchronized(共享对象) {
    // 只能原子性的代码
}

任何一个对象都有对象锁(标记),当线程尝试执行synchronized代码时,首先访问指定的共享对象对象,并尝试在lockpool中获取对象锁。

在寻找对象锁的过程中会释放之前占有的时间片,如果没有找到就一直等待,知道另外一个线程的代码执行完释放了对象锁,该线程在占有对象锁以后,该线程才在此进入就绪状态。

当synchronized出现在成员方法上时,静态方法锁的是类,否则是this。

使用synchronized嵌套有时会造成死锁问题。

线程分类

java中线程分为两类,

  1. 守护线程 代表为垃圾回收线程
  2. 用户线程 代表main线程

守护线程和用户线程的区别是,守护线程只要在所有用户线程结束以后自动结束。

设置守护线程的代码时 t.setDaemon

定时器

定时器作用式间隔特定的时间执行特定的程序。

sleep 方法可以实现最原始的定时器。

java.util.Timer 为java提供的定时器类。Spring框架中的SpringTask类也是通过该类实现。

指定定时任务使用

schedule(TimerTask task, Date firstTime, long period)

TimerTask是一个抽象类,这个抽象类实现了Runnable接口。

FutureTask

这种方式实现的线程,可以获取线程的返回值。

java.util.concurrent.FutureTask

创建一个FutureTask时,需要一个实现了Callable接口的对象作为参数,当执行FutureTask对象的run方法时,线程会在后台运行。

而当调用FutureTask对象的get方法时,当前线程会被阻塞,等待FutureTask对象的运行线程返回。

wait notify

o.wait(); FutureTask,

让正在o对象上活动的线程进入等待状态,直到被唤醒为止。

0.notify 唤醒正在0对象上等待的线程

o.notifyAll唤醒0对象上等待的所有线程

wait和notify方法必须建立到synchronized线程同步基础上。wait方法会把正在正在o对象上活动的线程进入等待状态,并释放锁🔒。但是notify方法只会通知,并不会释放锁。

线程在手动进入等待状态以后,必须手动通知其启动。

仓库,生产,消费

线程池

频繁创建线程和销毁线程需要时间。

线程池,线程的复用,线程的容器。

当程序第一次启动的时候,创建多个线程,保存到一个集合中。

Thread t = list.remove(0);

Thread t = list.removeFist();

当线程使用完,将线程还给线程池。

jdk1.5内置了线程池。

线程池的好处

java.util.concurrent

Executors 线程池的工厂类,用来生产线程池

newFixedThreadPool(int nThreads)

返回ExecutorService接口(线程池接口),用来从线程池中获取线程,调用start方法执行线程任务

submit 提交一个Runnable任务用于执行

shutdown 关闭销毁线程池

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值