JAVASE基础知识五——线程

一、线程
1、概念
进程:
就是在操作系统中打开的一个应用程序
线程:
就是应用程序的一个执行单元, 一条执行路径
一个进程至少有一个线程
一个进程也可以有多个线程, 这个进程就是多线程应用程序
在多线程应用程序中, 每个线程都是相互独立的, JVM分为栈区,堆区,方法区三块区域, 如果程序是多线程程序,JVM会给每个线程分配单独的一个栈空间, 即每个线程都有独立的线程栈
在这里插入图片描述
主线程:JVM是从main方法开始运行程序,运行main方法的线程就是主线程
子线程:也称用户线程, 就是在一个线程中开启的新的线程
守护线程:是为其他线程提供服务的线程, 如JVM中垃圾回收器就是一个守护线程, 当JVM中只剩下守护线程时,JVM就会退出

在多线程应用程序中, 操作系统是以进程为单位给程序分配系统资源, 进程中的多个线程争抢当前进程的系统资源。简单点儿说, 单核CPU在某个时间点只能执行一个线程, 因为CPU执行速度非常快, 可以快速的在各个线程之间进行切换, 对于用户来说,好像是多个线程在同时执行

2、创建线程

(1)定义Thread类的子类
class SubThread extends Thread{
	@Override
	public void run(){
		子线程要执行的代码
	}
}
SubThread t1 = new SubThread();
t1.start();

(2)定义Runnable接口的实现类
Class Prime implements Runnable{
	@Override
	public void run(){
		子线程要执行的代码
	}
}
Thread t2 = new Thread( new Prime() );
t2.start();

(3)义Callable接口的实现类
class Prime implements Callable<String> {
	public String call() throws Exception{
		子线程要执行的代码
		return “”;
	}
}
FutureTask<String> task = new FutureTask( new  Prime() );
Thread t3 = new Thread(task);
t3.start();
String result = task.get();

3、线程的常用方法

返回值方法描述
static intactiveCount() 当前活动线程的数量
static ThreadcurrentThread() 返回当前线程
ClassLoadergetContextClassLoader()
longgetId() 返回线程ID,每个线程都有唯一的ID
StringgetName() 返回线程名称
intgetPriority() 返回线程优先级
Thread.StategetState() 返回线程状态
ThreadGroupgetThreadGroup()
voidinterrupt() 中断线程
static booleaninterrupted() 判断线程是否被中断
booleanisAlive() 判断线程是否为活动线程,是否结束
booleanisDaemon() 判断线程是否为守护线程
booleanisInterrupted() 判断线程是否被中断
voidjoin() 线程加入(合并)
voidjoin(long millis)
voidrun()
voidsetDaemon(boolean on) 把线程设置为守护线程
voidsetName(String name) 设置线程名称
voidsetPriority(int newPriority) 设置线程优先级
static voidsleep(long millis) 线程睡眠
voidstart() 开启新的线程
voidstop() 终止线程
StringtoString()
static voidyield() 线程让步

4、线程完整生命周期
在这里插入图片描述

5、线程调度
(1)线程优先级
线程优先级取值范围: 1 ~ 10
线程默认优先级: 5
优先级越高,获得CPU执行权的机率越大
t1.setPriority( 10 ) 设置优先级
t1.getPriority() 返回优先级
(2)线程睡眠
Thread.sleep( millis)
静态方法, 通过类名直接调用
睡眠单位是毫秒, sleep()所在的线程进行睡眠
sleep()方法有受检异常需要处理, 如果是在run()方法中,只能捕获不能抛出
(3)线程中断
interrupt()
中断线程,一般是把睡眠/等待中的线程给唤醒
静态方法Thread.interrupted()
判断线程的中断状态, 如果返回true之后 ,会清除线程的中断标志
实例方法isInterrupted()
判断线程的中断状态,返回true之后 不会清除中断标志
(4)线程加入(合并)
t1.join()
在当前线程中加入t1线程, 当前线程转为等待状态, 一直等到t1线程执行完后,当前线程再转为就绪状态
t1.join(millis),
如果在millis毫秒内t1线程还没执行完, 当前线程不等了转为就绪状态
(5)线程让步
Thread.yield()
可以把当前线程由运行状态转为就绪状态
(6)线程终止
stop()可以终止线程, 过时了
想办法让run()运行结束 , 一般是设置一个标志, 在run()方法中不断的判断这个标志来决定是否结束

6、线程同步
(1) 线程安全问题:当多个线程同时操作堆区/方法区同一个数据时,可能导致数据不一致的现象,称为线程安全问题
出现了线程安全问题,怎么办?
1)每个线程都访问自己的局部变量,不会产生线程安全问题
2)如果多线程必须同时操作堆区/方法区同一个数据时, 可以采用线程同步机制

(2)线程同步
synchronized ( 锁对象 ){
同步代码块
}

(3)工作原理:
1)任何对象都可以作为锁对象, 每个对象都有一个内置锁
2)线程想要执行同步代码块, 必须先获得锁对象
3)线程a获得了锁对象,可以执行同步代码块, 会一直持有这个锁对象, 直到执行完同步代码块再释放锁对象
4)一个锁对象,在某一时刻最多只能被一个线程持有

(4)工作过程描述:
1)线程a获得CPU执行权,获得锁对象, 执行同步代码块
2)线程a在执行同步代码块期间, CPU执行权被线程b抢走了, 线程a转为就绪状态
3)线程b抢到CPU执行权 , 假设线程b也想执行同步代码块, 必须先获得锁对象, 现在锁对象被线程a持有, 线程b就会转到等待锁对象池中
4)线程a重新获得CPU执行权, 执行完同步代码块后, 会释放锁对象
5)等待锁对象池中处于阻塞状态的线程b可能获得锁对象后, 转为就绪状态

(5)同步代码块
同步代码块想要实现同步必须保证使用同一个锁对象,同步代码块只要使用了同一个锁对象就可以实现同步
经常使用一个常量对象作为锁对象
有时在实例方法中也会使用this对象作为锁对象
有时在静态方法中也会使用当前类的运行时类作为锁对象, 有人称它为类锁

(6)同步方法
当某个实例方法的整个方法体都需要进行同步,并且锁对象是this对象时, 可以直接使用synchronized关键字修饰这个实例方法, 称为同步实例方法
同步实例方法把整个方法体作为同步代码块,默认锁对象是this对象

当某个静态方法的整个方法体都需要进行同步,并且锁对象是当前类的运行时类对象时, 可以直接使用synchronized关键字修饰这个静态方法, 称为同步静态方法
同步静态方法是把整个方法体作为同步代码块,默认锁对象是当前类的运行时类对象

(7)死锁
多个线程进行同步时, 如果获得锁的顺序不一致,可能导致线程相互等待的情况,称为死锁
死锁条件:
1)一个锁对象只能被一个线程持有,互斥
2)一个线程获得了锁对象之后 ,会一直持有, 直到执行完同步代码块再释放
3)a线程获得了锁对象1, 还想获得锁对象2, 但是锁对象2在线程b手里持有
4)出现了相互等待的情况
如何避免出现死锁??
多个线程进行同步时, 保证获得锁的顺序都一样, 就不会出现死锁问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值