一、线程的创建
1、继承Thread类,重写run方法
优点:简单。缺点、;已经继承Thread类,不能再继承其他的类,不能共享实例变量。
2、实现Runnable接口,重写run方法。这种情况,多个线程可以共享Runnable实例变量。
3、使用Callable和Future创建线程,实现Callable接口。
第一步:
重写call方法,作为线程执行体,有返回值。
第二步:
创建Callable实例。
第三步:
创建FureTask实例,包装Callable对象,并封装Callable对象call方法的返回值。FutureTask实现Future接口,可以通过get方法获取call方法的返回值,调用改方法,导致程序阻塞,必须等到子线程结束才可以拿到返回值。isDone方法,如果Callable已经完成,返回true。可以使用ExecutorService。submit方法传入Callable实例,返回一个Future对象。
二、控制线程
1、join
在A线程的执行过程中,调用B线程的join方法,A线程将被阻塞,直到B线程执行完成。
2、线程让步yield
将线程转到就绪状态,让线程调度器重新调度一次(可能有重新转入的运行状态)
3、线程睡眠 sleep
调用该方法的线程进入阻塞状态,是调度器可以切换到其他线程。
三、线程池
1、调用Executors工具类产生线程池,一般有三种类型的线程池。
CachedThreadPool:创建一个具有缓存功能,创建于所需数量相同的线程,在回收旧线程时停止创建新线程。
FixedThreadPool:一次性分配固定数量的线程。
SingleThreadExecutor,创建只有一个线程的线程池,如果有多个人防,按提交顺序执行。
2、ExecutorService:调用submit方法,将Runnable或者Callable对象提交到线程池,返回null或者Future对象。调用shutdown方法,线程池不在接受新的任务,原来的任务仍然执行。调用shutdownNow方法,会停止所有正在执行的任务。
四、wait和notify
/**
* 使用同步代码块
*
* @param task
*/
private void addTaskToService(Task task) {
synchronized (mObject) {
if (mTaskService == null) {
return;
}
while (mTaskService.getWaitingCount() >= QUEUE_LIMIT) {
try {
Log.i(TAG, "addTaskToService: wait " + task.getId());
mObject.wait();
} catch (InterruptedException ex) {
}
}
Log.i(TAG, "addTaskToService Id: " + task.getId());
mTaskService.addTask(task);
}
}
任务完成,通知添加任务的线程:
synchronized (mObject) {
mObject.notifyAll();
Log.i(TAG, "onTaskDone notifyAll: " + task.getId());
}
五、Condition控制线程通信
对象使用Lock保证同步时,Java提供了一个Condition类保持协调。Condition实例绑定在一个Lock实例,调用Lock对象的newCondition方法可以得到Condition实例
/**
* 使用对象锁
*
* @param task
*/
private void addTaskToService2(Task task) {
mLock.lock();
if (mTaskService == null) {
return;
}
try {
while (mTaskService.getWaitingCount() >= QUEUE_LIMIT) {
Log.i(TAG, "addTaskToService: wait " + task.getId());
mCondition.await();
}
Log.i(TAG, "addTaskToService Id: " + task.getId());
mTaskService.addTask(task);
} catch (InterruptedException e) {
} finally {
mLock.unlock();
}
}
任务完成,通知线程继续往里面添加:
mLock.lock();
mCondition.signalAll();
Log.i(TAG, "onTaskDone signal(): " + task.getId());
mLock.unlock();
六、阻塞队列控制线程通信
BlockingQueue接口用来做为线程同步的工具,当向BlockingQueue添加任务,如果该队列已满,则线程被阻塞。当从BlockingQueue取出任务时,如果队列已空,则线程被阻塞。
常用的两种ArrayBlockingQueue,和LinkedBlockingQueue,可以用来控制线程池,任务的分发往队列里面添加任务使用:put,当任务完成时,使用remove。
新建一个阻塞队列,限制任务数为5:
private BlockingQueue<Task> mBlockingQueue = new ArrayBlockingQueue(5);
往
BlockingQueue里面添加任务:
/**
* 使用阻塞队列
*
* @param task
*/
private void addTaskToBlock(Task task) {
if (mTaskService == null) {
return;
}
try {
mBlockingQueue.put(task);
Log.i(TAG, "mBlockingQueue " + task.getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i(TAG, "addTaskToService Id: " + task.getId());
mTaskService.addTask(task);
}
任务完成,
BlockingQueue取出:
try {
mBlockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}