一、多线程的概念
多线程即是进程的多个执行路径,但并不能理解为这几个路径是同时执行的。在单cpu下应该是根据优先级调度法则轮流给这些个线程的执行时间片。
二、Java中的多线程
1)、如何创建一个线程
两种方式,实现Runnable接口和继承Thread类。一般建议使用Runnable接口。
2)、join、yield、sleep关键字的含义
Join即是将某一线程插入到当前线程中执行;yield使得与当前正在执行的线程有相同优先级的其它线程有执行的机会;sleep使当前线程休眠一段时间,可使得优先级低的线程有执行的机会。
3)、线程的优先级
Java中可以设定线程的优先级,其线程调度策略是基于优先级的抢占式调度法则,即优先级高的线程可以抢占优先级低的线程的cpu执行段,当优先级高的线程执行完毕后,优先级低的线程才有执行的机会。
4)、死锁
死锁的产生的基本原因是:线程1拿到了A资源的锁并等待B资源的锁,线程2拿到了B资源的锁并等待A资源的锁,由于两个线程互不释放各自的资源,导致两个线程均不能执行下去。
Java中并没有死锁的专门检测、避免机制,需要在程序中实现。通常的做法是:1、在全局中定义获得锁的顺序,线程按照顺序获得资源锁,反向释放资源锁。2、线程要么一次性获得所有的锁,要么不获得任何锁。
三、线程同步(生产者和消费者问题)
多线程环境下,一个资源可能有多个线程在使用,产生了线程同步的问题。Java中用synchronized关键字对对象或者方法进行同步。该关键字的含义是对对象或者方法进行加锁以保证在同一时间段只有一个线程使用。Wait是当某个线程需要获得对象资源时而其它线程正在使用时则等待,此时该线程会进入该对象的线程等待池。notify(notifyall)关键字是唤醒某个对象资源线程等待池的线程,表明已有线程释放了该资源。
一个经典的问题是生产者和消费者的问题,在附录中有测试demo
四、线程池的概念和用法
在JDK1.5以后,java的API中有了线程池,好像有多种类型的线程池,目前只用过ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler
),其中corePoolSize为核心线程数(即线程池中的长工)、maximumPoolSize为最大线程数(长工+短工),keepAliveTime为短工无任务时的存活时间,unit为时间单位,workQueue为任务队列,Handler为拒绝任务的处理器。关于详细的线程池的讲解不在这里一一展开。
五、Android下的多线程
在android中每一个APP应用是在一个单独的dalvik虚拟机单一的linux进程中,每一个应用有一个主线程(main thread)这个主线程负责分发按键的响应等与用户交互的事件响应,在这个主线程内不能有太长时间的阻塞,线程阻塞超过5秒后就会报程序无响应的错误。因此一些复杂的、耗时的操作必须开启新的线程去操作,但是在android的框架中UI元素是必须在主线程才能更新的,所以在后台的复杂逻辑完成后,要更新与用户交互的UI元素又必须回到主线程中。在android中有两个重要的工具可以利用,Handler和AsyncTask。
Handler可以处理一些消息和将一些Runnable借口运行在其当前的线程中。目前应用的最多的是主线程创建一个Handler实例,并将该实例传递给后台运行的线程,后台的线程完成其工作后,使用该Handler发送一个message,这时在主线程中接受到该消息,然后进行一些UI的更新。至于参数的传递等细节的问题,可以查阅Message类的说明,在这里就不一一展开。
AsyncTask异步任务是android专门设计来解决后台线程完成后更新主线程中的UI元素的一个类。其三个泛型参数为Param、Process、Result。Param为传入参数、Process为进度、Result为后台任务完成后传递到主线程中的参数。该类中有四个可以重载的方法:
1、 onPreExecute:在后台逻辑执行前需要的准备工作在这里完成。UI线程【即主线程】在doInBackground前调用该方法。【注意该方法是执行在UI线程中的】
2、 doInBackground:后台线程调用该方法完成复杂耗时的逻辑,可以通过publishProgress方法来更新实时的任务进度到UI,publishProgress需要自己实现
3、 onProgressUpdate:当publishProgress被调用后,UI线程调用该方法更新UI。
4、 onPostExecute:当doInBackground完成后,将Result传递到该方法,UI线程调用。
好了,今天就啰嗦这么几句。发现写博客怎么这么耗时啊。
附录:生产者和消费者的经典问题,我们设置一个栈,生产者负责生产面包到栈中,消费者负责消费栈中的面包
1、面包对象
public class BreadBean {
private int id;
private String name;
public BreadBean(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2、栈
/*
* 用于同步的栈
* */
public class AsynStack {
private BreadBean[] mstack = new BreadBean[10];
private int index = 0;
public synchronized void push(BreadBean bean) {
while(index == mstack.length){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mstack[index] = bean;
index++;
this.notifyAll();
}
public synchronized BreadBean pop(){
while(index == 0){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
index--;
BreadBean bean = mstack[index];
return bean;
}
}
3、生产者
public class Producer implements Runnable {
private AsynStack mstack;
private boolean stpFlag = false;
private String name;
private int id = -1;
public Producer(AsynStack mstack,String name) {
super();
this.mstack = mstack;
this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(!stpFlag){
BreadBean bean = new BreadBean(++id, name);
mstack.push(bean);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public boolean isStpFlag() {
return stpFlag;
}
public void setStpFlag(boolean stpFlag) {
this.stpFlag = stpFlag;
}
}
4、消费者
public class Consumer implements Runnable {
private AsynStack mstack;
private boolean stpFlag = false;
private String name;
public Consumer(AsynStack mstack, String name) {
super();
this.mstack = mstack;
this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(!stpFlag){
BreadBean bean = mstack.pop();
System.out.println(name + " consume " + " bean produced by " + bean.getName() + " id is: " + bean.getId());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public boolean isStpFlag() {
return stpFlag;
}
public void setStpFlag(boolean stpFlag) {
this.stpFlag = stpFlag;
}
}
5、测试程序
ublic class AsynStackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AsynStack stack = new AsynStack();
Producer p1 = new Producer(stack, "producer1");
Producer p2 = new Producer(stack, "producer2");
Producer p3 = new Producer(stack, "producer3");
Producer p4 = new Producer(stack, "producer4");
Thread producer1 = new Thread(p1);
Thread producer2 = new Thread(p2);
Thread producer3 = new Thread(p3);
Thread producer4 = new Thread(p4);
Consumer c1 = new Consumer(stack, "consumer1");
Consumer c2 = new Consumer(stack, "consumer2");
Consumer c3 = new Consumer(stack, "consumer3");
Consumer c4 = new Consumer(stack, "consumer4");
Thread consumer1 = new Thread(c1);
Thread consumer2 = new Thread(c2);
Thread consumer3 = new Thread(c3);
Thread consumer4 = new Thread(c4);
producer1.start();
producer2.start();
producer3.start();
producer4.start();
consumer1.start();
consumer2.start();
consumer3.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
p1.setStpFlag(true);
p2.setStpFlag(true);
p3.setStpFlag(true);
p4.setStpFlag(true);
c1.setStpFlag(true);
c2.setStpFlag(true);
c3.setStpFlag(true);
c4.setStpFlag(true);
}
}