线程
1. 进程(Process)
进程通常可以理解为正在运行的程序,有自己独立的内存空间,有操作系统负责分配资源,例如:CPU的调度。多个进程可以并发执行。对于单个CPU,并发从宏观上理解是在同时执行,但是在微观上是顺序执行。
2. 线程(Thread)
线程是进程中的一个顺序执行流(一个线程执行多个任务时,这多个任务是顺序执行的),一个进程可以启动多个线程,多个线程可以共享资源并发执行。
3. 线程对象的创建
在java中所有的线程对象的类型为Thread类型,我们创建线程的方式通常有两种:
1)创建Thread类的子类对象,重写Thread类的run()方法,并在run方法中执行任务。
2)创建Runnable接口或者Callable接口的子类对象,重写run()或call()方法,作为线程的任务。
4. 两种创建方式的优缺点:
1)采用继承Thread类的方式创建:
a. 缺点:因为线程已经继承了Thread类,所以不能再继承其他父类。
b. 优点:编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
2)采用Runnable、Callable接口方式创建:
a.线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
b. 在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
说明:线程对象创建以后不会自动执行,需要调用Thread类的实例方法start()方法启动线程,线程启动以后,如果获得了CPU会自动执行run()方法。而且当我们启动线程以后不一定会立刻执行此线程。
5. 线程对象的状态及相关方法的应用
1)新建状态(new Tread)
2)就绪状态(可运行状态):start()
3)运行状态(正在执行run方法)
4)阻塞状态(线程不可获得CPU)sleep(),interrupt()
5)死亡状态(线程已经运行结束)
6. 线程中常用的方法
1)构造方法(重要,参考第3条)
2)setName(String name):给线程命名
3)currentThread():获得当前线程
4)getName():得到线程的名字
5)start():启动线程,线程处于就绪状态
6)run():在此方法执行业务逻辑,此时线程线程处于运行状态(不会直接调用)
7)sleep() :线程让出cpu处于阻塞状态,休眠(静态方法)
8)interrupt():唤醒正在休眠的线程,被唤醒的线程处于就绪状态
9)join():调用此方法的线程优先执行,其他线程处于阻塞状态
10) setDaemon(boolean flag):当flag的值为true时,表示设置此线程为守护线程(精灵线程),可以将守护线程理解为服务性线程。当没有其它线程在执行时,守护线程会自动销毁。(必须放在start())
11) yeild():让出cpu,不会阻塞线程,线程处于就绪状态(静态方法)
12) isAlive():判断这个线程是否还活着
7. 线程的同步
所谓线程同步通常可以理解为,多个线程在共享数据集上的互斥和协作。
1)线程同步的作用:
a. 保证线程安全(数据的安全)。
b. 保证数据的合理性。
2)线程的互斥:
a. 多个线程在共享数据集上排队执行。
b. 如何实现:在共享数据集所在的代码块上添加一把锁,这个锁通常称之为对象锁。获得锁的线程对象优先执行,其他线程等待。当获得了对象锁的线程执行完代码块会释放锁,其他线程竞争锁,然后执行代码块。
3)代码中的应用(线程同步的方法):
a.同步代码块
synchronized (对象锁) {
被锁的共享数据集
}
b. 同步方法(默认同步锁)
public synchronized void sale(){
被锁的共享数据集对象锁默认为this;
}
public static synchronized oid sale(){
被锁的共享数据集对象锁默认为类对象(例如TicketTask.class)
}
c. 同步锁(lock):可以具有比上述两种方法更灵活的结构
private eentrantLock lock = lock ReentrantLock();
lock.lock();
………………
lock.unlock();
说明:我们使用加锁的方式实现了线程的互斥,保证了数据的安全,但同时也会降低系统的执行效率,所以在一些线程安全的环境下尽量不要使用同步代码块或同步方法。
8. 类的加载:
Point p=new Point();
1)加载类(将类读到内存),存储到代码区(Code Area)在加载的过程中假如有静态变量,静态代码块,它从上到下依次初始化。
2)为对象分配堆内存(随机分配)
3)在堆内存初始化实例变量(从上到下)
4)调用构造方法。
9. 线程同步(线程协作)
当多个线程在共享数据集上要实现交互操作,通常要借助object类中的wait,notify,notifyall方法实现。
1)Wait():调用此方法的线程会处于等待状态同时会释放对象锁。
2)Notify():调用此方法用于通知具备相同锁对象的线程开始执行。同时调用此方法的线程会释放锁。
3)Notifyall():用于通知多个具备相同锁的对象。
注意:1) 这些方法要应用在同步代码块或同步方法内部
2)这些方法由对象锁调用。
10. 线程通信:
1) 传统线程通信(同步代码块、同步方法和wait,notify,notifyall方法)
2) 使用Condition控制线程通信(同步锁和await、signal、和signalAll方法)
3) 使用阻塞队列(BlockingQueue)控制线程通信
抛出异常 | 不同返回值 | 阻塞线程 | 指定超时时常 | |
队尾插入元素 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
队头删除元素 | remove() | poll() | take() | poll(time,unit) |
获取、不删除元素 | element() | peek() | 无 | 无 |
线程池
系统启动一个新线程的成本比较高,因为要涉及到与操作系统的交互,使用线程池可以很好地提高性能,尤其实在程序中需要创建大量生存周期很短暂的线程时,更应该考虑线程池
创建线程池的方式:
使用Executor Service或者ScheduledExecutorService创建,方法如下:
ExecutorService es =
//1.1创建只有一个线程的线程池
//Executors.newSingleThreadExecutor();
//1.2创建上限固定的线程池
//Executors.newFixedThreadPool(2);
//1.3创建一个上限数量没有限定的线程池
Executors.newCachedThreadPool();
ScheduledExecutorService ses=
//2.1创建一个线程的线程池,可以执行延迟任务
// Executors.newSingleThreadScheduledExecutor();
//2.1创建一个上限固定的线程池,执行延迟任务
Executors.newScheduledThreadPool(2);
线程的通讯机制:
1) 主要步骤:
a.Message (消息对象,数据的载体);
b.MessageQueue(消息队列,存储多个消息)
c.Looper(迭代器,迭代消息队列)
d.Handler(发送,处理消息)
核心思想:给哪个线程发消息,就获得与哪个线程的Looper相关联的Handler其中,主线程中有默认的Looper,主线程启动时已创建,并且关联一个消息队列。在工作线程中要获得主线程中的Looper,可以通过如下方法:
Looper.getMainLooper();
工作线程创建Looper的具体步骤:
在工作线程中创建Handler,可以通过如下方法:(工作线程中通过主线程的Looper构建Handler)
new Handler(Looper.getMainLooper());
Handler中借助sendMessage方法发送消息,借助handleMessage方法处理消息sendMessage方法运行在哪个线程取决于在哪个线程。handleMessage方法运行在哪个线程取决于handler关联的Looper.
3. 何为任务调度:
所谓任务调度,就是操作系统为线程分配CPU执行任务。
1)分配CPU的方式通常有两种方式:
a. 按时间片
b. 按优先级
3) Timer类在任务调度中应用
对于任务数量比较少,比较简单的一些调用可以借助Timer类的对象实现。
a. 构建Timer对象(看类型,看构造方法)
b. 借助Timer对象的schedule方法执行任务,任务类型为TimerTask类型,将要执行的任务写到TimerTask对象的方法中。
c. 任务结束以后,调用timer对象的cancel退出调度。
4) ScheduledExecutorService类在任务调度中应用
a. ScheduledExecutorService接口继承ExecutorService,并此基础之上扩展了一些相关方法。
b. 此接口类型的对象,用于管理一个线程池,可以通过线程池中的线程,执行任务。
c. 假设要通过ScheduledExecutorService接口执行任务调度,首先要借助Executors的方法构建ScheduledExecutorService的实现类的对象,然后借助此对象的相关方法再去执行任务。
4. Android 中的线程应用(重点,难点)\
1) Android 中线程对象应用机制
a. 所有的UI操作都在主线程(UI线程)执行.
b. 所有的耗时操作都在工作线程(自己构建的)。
c. 说明:在工作线程中更新UI可以调用runOnUiThread(Runnable r)方法
5. HandlerThread类的应用
此类为Android中提供的一个工具类(本质上是一个线程类型,继承Thread),借助此类主要是为了简化工作线程中Looper对象的创建。在此类中封装了Looper对象的创建,获得,销毁过程。
6. Handler对象其它方法应用
1)sendMessage(msg)
2)handleMessage(msg)
3)sendEmptyMessage(int what)
4)postDelay(Runnable r); 底层发送延迟消息
7.Message 对象其它方法
1)1.obtain(); 首先从消息池获得消息,消息池没有则创建。
Message msg=Message.obtain();
2)obatin(.....) 重载
3)sendToTarget(); 发送消息
Message.obtain(h,5).sendToTarget()