一、简单定义
什么是进程
2.线程与进程
线程由进程创建。
3.并发与并行
二、线程的使用
使用 继承 thread 类。重写 run 方法
实现 Runnable 接口,重写 run 方法,并将其对象传入 thread 的构造器中创建 thread 对象
1.Extend thread
1 | public class threadsEXtend { |
2.implement Runnable 解决该类已经有 基继承的类
Thread 中具有代理模式的设计模式。
具有 一个 runnable 类型 的 Target
然后还有一个 构造器,可以接受一个 实现了 runnale 接口的类。
因为 runnable 接口没有 start 方法,创建 线程需要调用 start 方法,所以需要 thread 类进行代理。
1 | package com.threadUser; |
3. extend 和 implement runnable 的区别
Runnable 更适合 多个线程共享一个资源的情况,并且避免了单继承的限制
1
2T3 t3=new T3();
4.通知线程退出
- 线程完成任务后,会自动退出
- 可以使用==控制变量==来控制 run 方法退出的方式停止进程,即通知方式。
1 | 安丽 |
5.常用方法
- 1.setName //设置线程名字
- 2.getName //返回线程名称
- 3.start 启动该线程,jvm 底层调用该进程的 start0 方法
- 4.run //直接调用线程对象的 run 方法
- 5-setPriority //更改线程的优先级
- 6-getPriority //获取线程的优先级
- min –1
- max –10
- normal –5
- 7-sleep //让线程指定休眠 xxx 毫秒 (暂停执行)
- 8- interrupt //中断==线程的休眠==
- 9- yield :线程的礼让,让出 CPU ,让其他线程先执行,但礼让的时间不一定,所以礼让也==不一定成功==。
- 是否礼让由系统资源决定,操作系统内核负责处理,这一块 java 无法控制
- 10- join:线程的插队,插队的线程一旦插队成功,则肯定==先执行完插入的线程的所有任务==。
- 小弟让大哥先吃完包子自己再吃。
6.用户线程和守护线程
1 | 线程对象.setDaemon(true) --->守护进程。 |
注意点
- 当处于 Runnable状态时,并不是一定在进行,而是由 操作系统的线程调度器负责 调配运行。—>由操作系统内核决定。(内核态)
- 官方文档为 6 种状态,但一般 又将 runnable 细分为两种转态,即有7 钟转态
可以使用 jconsole 工具 查看线程
三、生命周期
1.生命周期
2.线程同步机制
1)线程同步机制 Synchronizd
一个敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。
2.synchronize 使用
四、锁
这里的同步方法是否是 静态的 非常重要。—Synchronized
如果是 this ,则是 当前对象,如果不同对象,不会造成堵塞。
如果是==静态(stastic)==, 则是 加在该类的 Class 中(类加载的知识) ,该==类的不同对象==,会造成==堵塞==。
1.注意事项和细节:
1.同步方法如果没有使用 static 修饰,默认锁对象就是 this
2.同步方法使用了 static 修饰,默认锁对象:当前类的 Class 对象(通常通过 类名.class获得)
3.实现锁的步骤
1.分析需要上锁的代码
2.选择==同步代码块(优先考虑)==或同步代码
3.==要求多个线程的锁对象为同一个。==
- 什么意思?
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Thread1{
public synchronized void sayhi(){
System.out.println("hi");
}
}
思考:这里的 hi 能锁住吗?
分析:
1.同步方法没有使用 static 修饰,那默认锁对象为 this。
2.而想要调用 sayhi 方法,就要使用 new Thread1().sayhi
3.而第2步中每次 调用都 new 了一个新对象,即此时如果使用 不同对象的 start 方法进行创建多线程。
4.那此时,多个线程的锁对象就是他们对应的那个对象---->即不是同一个对象。不同的线程争夺的是不同的锁,那就无法锁住。
怎么解决?
1.绑定同一个对象,其他的对象,例如新建一个 object 对象
2.给方法加上 static ,使其绑定类的Class 对象
- 什么意思?
2.线程死锁
多个线程都占用了对方的锁资源,但不肯相让,导致了死锁。
一个案例
1 | package com.hspedu.syn; |
3.释放锁
释放锁的问题。
下列操作不会释放锁
- sleep、yield
太困了,但还在厕所里面。 - 线程被挂起.suspend()。
六、一些疑问
- 为什么调用的是 start 方法,而不是直接调用 run 方法
A: 直接调用 run 方法,那就是相当于普通的方法调用,只会在主栈中调用,不会创建新线程。而调用 start 方法可以创建新 线程并 会自动调用 run 方法。–>看源码分析
1 |
|