多线程并发编程
并发:
采用分时技术同时执行多个程序的方式
进程:
一个运行环境,具有所需的计算资源和存储资源,每个进程运行一个程序,多个进程通过分时技术分享cpu的计算资源,通过地址空间映射技术分享内存的存储资源,操作系统全权负责进程的创建,管理,调度和删除

线程:
指令序列(算法)单独创建的线程,每个线程负责执行一个算法,进程中创建多个线程
进程和线程关系:
进程包含线程,一个进程可以包含多个线程,进程中的存储资源可以被进程中的各线程所运行的算法共享
一个进程运行一个程序
一个线程运行一个算法
一个进程可以包含多个线程
单线程串行程序
每个Java程序运行时都会单独创建一个进程,该进程自动包含一个主线程–main。
同一线程的算法内部是串行执行的。
如果程序的主方法调用某个子方法,该程序仍然属于单线程串行程序。
多线程并发程序
多个线程之间通过分时技术并发执行
子线程编写步骤
1,将算法封装成一个可运行的算法对象(实现Runnable接口)
注:可以使用匿名类创建算法对象
2,创建线程对象(Thread)在线程对象中运行算法对象
注:
线程调用start()方法启动线程,计算机执行算法对象中的run()方法,线程对象可以在执行过程中响应外部中断请求,当程序中的主线程和所有子线程都执行结束后,进程随之结束,进程结束时,守护线程自动结束。
3,定义算法类时可以直接继承Thread类(Java是单继承)
两种中途停止子线程的方法
1,通过线程类Thread的方法成员interrupt()外部终止。
2,将子线程设为守护线程,在进程结束时自动停止
多线程并发调度
Java虚拟机负责线程管理和执行调度
线程状态:
描述线程对象状态的枚举类
线程优先级
优先级从1到10
1为最低,10为最高,默认优先级为5
线程对象可以通过setPriority()getPriority()修改和获得自己当前优先级
单核cpu:分时技术
多核cpu:不同核上运行线程
多线程之间的并发与互斥
多线程中的互斥操作:
假设每个线程运行一个算法,两个线程中的算法不能重叠交叉执行,则这两个算法被称为互斥操作。
如果多个线程共享数据,在不同线程中同时访问共享数据就可能是互斥操作。
Java语言中使用同步(synchronization)机制,来避免多线程切换,带来的重叠交叉算法错误
互斥操作算法的同步
同步方法:
使用关键字synchronized将互斥操作算法定义成一个同步方法
如果某个线程同步方法执行,其他线程中的该同步方法互斥的方法都不会执行,直到执行结束
synchronized 方法类型 方法名(形参列表){
......
}
同步语句:
指定特定的对象加锁,同步方法是对当前对象加锁
同步语句一般用来锁定被共享的数据
synchronized(对象名){
......
}
同步机制实现
对象锁服务
多线程协同
定义:同步线程间的互斥操作,控制各线程的运行次序(等待唤醒机制)
经典实例:
运行示意图
等待唤醒机制
空转等待(产生死锁):
在同步方法中,循环查看数据标记,等待数据录入,再做后继续操作。不会释放对象锁。
阻塞等待(等待-唤醒机制):
在同步方法中使用阻塞等待,当前线程会释放对象锁(有效避免死锁),然后暂停执行并进入阻塞状态,cpu去执行其他线程,阻塞线程需要其他线程唤醒后再继续执行
wait()-----阻塞等待方法
notifyAll()-----阻塞唤醒方法
此二者方法只能在同步方法或同步语句内使用
wait()会产生interrupted Exception
wait()和notifyAll()一一对应,一个线程阻塞必须由另一个线程唤醒
线程安全类
已实现同步机制和等待唤醒机制的类
线程安全:
String,StringBuffer,vector,Hashtable等
非线程安全:
StringBuilder,ArrayList,LinkedList等
单线程程序应选用非线程安全,执行效率高
定时执行线程
本地日期时间类:
定时任务类TimerTask:实现类Runable接口,是一个算法类,用来描述定时执行的操作任务。
定时器类Timer:创建定时执行的守护线程,执行定时任务TimerTask的算法对象。
Swing框架中的线程
事件分发线程
响应组件事件的监听器算法代码都会在事件分发线程中执行
注:由于图形组件操作是线程不安全的,Swing框架中,应当将算法代码交由事件分发线程统一执行
通过事件分发线程操作图形界面
1.将操作图形组件的算法代码包装成线程对象(实现Runnable接口)
2.调用javax.swing.SwingUtilities类中的静态方法invokeLater(),将算法对象提交给事件分发线程统一调度,执行
这样避免了子线程和事件分发线程的冲突,多线程并发,事件分发线程按序执行
多线程并发绘图
将绘图算法包装成线程对象
调用invokekater()将其提交给事件分发线程统一调度