Java学习16 线程
来源:互联网 发布:js 数组初始化0 编辑:程序博客网 时间:2024/06/05 08:40
线程基础
线程是一个程序内部的顺序控制流。
- 进程:有独立的代码和数据空间(进程上下文),切换的开销大
- 线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小
- 多进程:操作系统同时运行多个任务(程序)
- 多线程:同一应用程序中有多个顺序流同时执行
线程的概念模型
- 虚拟的CPU:由java.lang.Thread类封装和虚拟;
- 代码:传递给Thread类对象执行
- 数据:传递给Thread类对象处理
创建线程
java.lang.Thread类
run()方法:线程体
方法1:使用Runnable接口创建线程
- 定义类实现Runnable接口,重写run()方法;
- 创建Thread对象,封装Runnable接口实现类对象;
- 调用Thread对象的start()方法。
public class TestThread { public static void main(String[] args) { MyRunner r = new MyRunner(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); }}class MyRunner implements Runnable { @Override public void run() { for (int i = 0; i < 30; i++) { String s = Thread.currentThread().getName(); System.out.println(s + ":" + i); } }}
多线程共享代码
多线程之间可以共享代码和数据MyRunner r = new MyRunner();Thread t1 = new Thread(r);Thread t2 = new Thread(r);
线程 虚拟CPU 代码 数据 t1 Thread类对象t1 MyRunner类的run方法 MyRunner类对象r t2 Thread类对象t2 MyRunner类的run方法 MyRunner类对象r
方法2:直接继承Thread类创建线程
- 继承Thread类,重写run()方法
- 创建Thread子类对象
- 调用对象start()方法
这里写代码片
两种方式比较:
使用Runnable接口创建线程:
- CPU/代码/数据分开,模型清晰
- 线程体run()方法所在类还可以继承其他类
- 有利于保持程序风格一致性
直接继承Thread类创建线程:
- Thread子类不能在继承其他类
- 编写简单,run()方法当前对象就是线程对象,可直接操纵
后台线程/守护线程/精灵线程
- 后台处理(Background Processing)
- 后台线程/守护线程/精灵线程(Background Thread/Daemon Thread):如垃圾回收线程、定时器线程
- 用户线程(User Thread)
- 主线程(Main Thread)
- 子线程(Sub Thread)
方法:
boolean isDaemon()
void setDaemon(Boolean on)
注意:当一个应用程序的所有用户线程都执行结束后,JVM都会停止后台线程的执行(当可能存在延时)。
GUI线程
常见GUI线程
- AWT-Windows
线程:操作系统获取底层事件信息
- AWT-EventQueue-n
线程:GUI事件处理队列,从AWT-Windows
线程获取事件消息
- AWT-Shutdown
线程:负责关闭已经打开的抽象窗口工具,释放GUI所有占用的资源,等其他线程退出后才执行
其他非GUI线程:
- DestoryJavaVM
:释放所占用的系统资源,卸载JVM,清除内存class和内存空间。在主线程main执行结束后被拉起
线程控制
线程生命周期
- 新建:start()进入就绪状态
- 就绪:线程调度器调度后进入运行状态
- 运行:阻塞事件(如IO读取)进入阻塞状态;run()执行完毕进入终止状态
- 阻塞:阻塞解除进入就绪状态
- 终止:终止后不能重新start()
线程优先级
- 范围1~10,缺省为5
- 子线程优先级默认与父线程相同
方法:
int getPriority()
void setPriority(int newPriority)
静态常量:
Thread.MIN_PRIORITY=1
Thread.MAX_PRIORITY=10
Thread.NORM_PRIORITY=5
线程控制中,不能依赖线程优先级,来决定线程执行的先后顺序
线程串行化
线程运行过程中,依赖另一线程的运行结果(或等待运行一段时间),进入阻塞状态
- final void join()
- final void join(long millis)
- final void join(long millis, int nanos)
线程休眠
- static void sleep(long millis)
- static void sleep(long millis, int nanos)
线程让步
让运行中的线程主动放弃当前CPU处理机会;但不是使线程阻塞,而是转入就绪状态
- static void yield()
线程的挂起和恢复
- final void suspend()
- final void resume()
终止线程
- 不提倡使用Thread下
stop()
方法
线程控制基本方法
线程的同步
临界资源问题
原因是对共享数据访问操作的不完整性
互斥锁
- 保证共享数据操作的完整性
每个对象都对应有一个可称为“互斥锁”的标记,保证在任一时刻,只能有一个对象访问该对象
关键字synchronized:表明对象在任一时刻,只能有一个线程访问
两种用法:
方法声明(同步方法):public synchronized void push(char c) { /*...*/ }
修饰语句块(同步块):
public char pop(){ synchronized(this){ /*...*/ }}
线程死锁
举例:
这里写代码片
线程同步通讯
为避免死锁,在线程进入阻塞状态时,应尽量释放其锁定的思源,以为其他的线程提供运行的机会
- final void wait()
- final void notify()
- final void notifyAll()
运行态线程调用对象的wait()方法:① 线程进入阻塞状态(阻塞在对象wait()池中);②解除调用者对象的锁定状态。
其他线程调用同一对象的notify()/notifyAll()方法:获取对象锁后,进入就绪状态。suspend()/resume()不同,其不会释放资源
// 生产者-消费者问题这里写代码片
多线程编程专题
线程见数据传输
PipeInputStream/PipeOutputStream
- 管道流
- 不提倡在单个线程中使用管道流,而是在多个线程中使用
- 一般也不在高并发环境下使用,避免死锁
类的同步性与线程安全
- Vector(同步安全) vs. ArrayList(非同步安全)
分析:Vector是安全的,但size()和elementAt()方法调用存在状态依赖
修改:
定时器
- Timer
- schedule方法
- TimerTask
- Java学习16 线程
- Java并发学习笔记(16)守护线程,线程组
- 【Java学习笔记】16:线程的协调
- java学习日记(线程)
- Java线程学习
- java线程学习基础
- java线程学习总结
- JAVA学习【知】线程
- Java学习之多线程
- java线程初步学习
- Java线程学习11.30
- java线程学习例子
- 关于java 线程学习
- java线程学习总结
- Java 线程池学习
- java线程的学习
- java线程的学习
- java线程池学习
- 自頂向下,逐步求精
- 深入理解java-ThreadLocal
- js arguments使用
- TCP CLOSE_WAIT 过多解决方案
- Linux 驱动—LCD学习一:实践篇
- Java学习16 线程
- Centos7 安装RabbitMQ 详解
- 用SpannableString打造绚丽多彩的文本显示效果
- 59.56.97.66全新升级面对更好的你,更高防御更好的保护你
- cnn matlab实现mnist
- Qt5.8.0 mingw 编译QOCI
- linux下应用crontab对mysql数据库进行定时备份
- Absible 自动化部署工具简介和入门
- 分布式实时日志分析解决方案 ELK 部署架构