Java线程基础

一、什么是线程

线程是进程的一个实体,线程不能够独立存在,进程作为操作系统资源分配的基本单位,线程是进程的一次执行路径,一个进程中可以有多个线程,同一进程的线程可以共享进程的资源。

因此线程时实际上是CPU执行调度的基本单位。Java中,main函数就是一个JVM进程。

二、创建线程的方式

1、继承Thread类
1)定义一个类extends Thread类,并重写run()方法,在run()方法中执行线程的任务
2)创建这个类的对象,并调用该对象的start()方法来启动线程。
但是Java是单继承,继承了Thread类后,就不能继承其他类了
2、实现Runnable接口
1)定义一个类implements Runnable接口,并重写run()方法,同样地在run方法里执行线程的任务
2)创建这个类的实例,并将这个对象作为参数传给Thread类的一个对象。
3)调用Thread对象的start()方法,启动线程。
3、使用Callable和Future
Callable与Runnable接口,不同的是前者有返回值,而后者没有,Callable的返回值就是一个Future接口的对象。一般使用实现Future接口的实现类FutureTask,内部有几个方法方便判断线程执行的状态:
boolean cancel(boolean mayInterruptIfRunning):取消Future接口里的Callable任务;
V get():返回Callable任务的结果,该方法会被阻塞,直至任务返回结果;
V get(long timeout,TimeUnit unit):返回Callable任务的结果,该方法会被阻塞timeout时间,超过这个时间后没有得到结果也会返回并抛出TimeoutException。
boolean isDone():任务是否完成;
boolean isCancelled():任务是否在正常完成前被取消。

1)创建Callable接口的实例,并实现call()方法,在call()方法内执行线程的任务。
2)创建FutureTask类的实例,并包装Callable对象,该实例封装了call()方法的返回值
3)创建Thread的实例,并将FutureTask对象传入Thread实例,调用start()方法启动线程
4)使用FutureTask对象的get()方法取得返回值。

4、使用线程池完成线程的提交与执行
线程池都实现了Executor接口,并实现了execute()接口,接收一个Runnable实例,执行线程的任务,具体实现方式后续在线程池的原理中介绍。

三、线程的方法

1、wait方法
并不是所有线程使用的方法都在Thread类,Java的根类是Object类,把所有对象都会用到的方法都放在了这个类里,例如,线程的wait()和notify()系列方法。

为什么wait()和notify()方法在Object类里?简单来说,在使用synchronized实现同步时,等待与唤醒必须是同一个锁,这个锁可以从任意对象的对象头中获取,所以wait()和notify()方法在Object类里。

  • wait()
    当一个线程获取到同步锁后,调用这个方法,则该线程被挂起,直至有1) 其他获取到同一个锁的线程调用notify()或notifyAll()方法,2)其他线程调用了该线程的interrupt()方法,这时线程抛出InterruptException异常。
    为了防止线程的虚假唤醒,一般在while循环中调用wait(),循环判断唤醒条件是否满足。
  • wait(long timeout)
    可以设置超时时间,如果超过超时时间仍然没有其他线程调用notify()或notifyAll()方法,则该线程返回
  • wait(long timeout, int nanos)
    内部调用wait(long timeout),只有在nanos>0才使timeout加1。

2、notify/notifyAll方法
一个线程调用notify()会唤醒在同一个锁上被wait()方法阻塞的某个线程,具体唤醒哪个线程是随机的。而调用notifyAll()会唤醒在该锁下所有被wait()方法阻塞的线程。被notify唤醒的线程不会立刻获取到锁,仍然需要和其他线程竞争。

3、join方法
该方法在Thread类中,若线程A调用了线程B的join()方法,则线程A被阻塞,直至线程B执行完毕,若在A阻塞期间有线程调用了A的interrupt(),则A抛出InterruptException异常返回。

4、sleep方法
该方法在Thread类中,若线程调用了sleep(),则该线程会让出CPU执行时间且不参与CPU调度,但是线程获取的资源不会释放,即仍然持有锁。当sleep到指定时间,则该线程返回并处于就绪状态。若在sleep期间有其他线程调用了interrupt方法,则该线程抛出InterruptException异常返回。

5、yield方法
该方法在Thread类中,若线程调用yield方法,则该线程让出CPU执行权,即使时间片没有使用完,接着CPU进入下一轮调度,选择具有最高优先级的线程,该线程仍然可能被选中。
yield与sleep方法的区别在于,sleep会阻塞线程一段时间,这段时间内线程不参与调度,yield只是让出CPU不阻塞,下次调度仍然可能被选中。

6、interrupt、isInterrupted、interrupted方法

  • interrupt(),中断线程,设置线程的中断标志为true,当线程A因执行wait、sleep、join方法被阻塞挂起时,线程B调用A的该方法,A会抛出InterruptException异常返回。
  • isInterrupted(),检查线程是否被中断,不清除线程中断标记。
  • interrupted(),检查线程是否被中断,但是会清除线程中断标记。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值