线程

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()

 

 


线程池

系统启动一个新线程的成本比较高,因为要涉及到与操作系统的交互,使用线程池可以很好地提高性能,尤其实在程序中需要创建大量生存周期很短暂的线程时,更应该考虑线程池

  1. 创建线程池的方式:

使用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. 线程的通讯机制:

  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()