多线程开发:(多任务、分时设计)
进程:一个执行中的程序、一个进程有一个独立的内存空间、一组系统资源。内部数据、状态完全独立。
线程:一个进程可以包含多个线程.
多线程:(计时器案例)
- 单个程序中:运行多个不同的线程、执行不同的任务(多个语句可以看上去几乎同一时间内同时完成)
- 完成某特定功能的代码,程序中单个顺序的流控制
- 同类多个线程共享一块内存空间和一组系统资源
Java中的线程:
java.lang.Thread类,生成一个Thread类的对象后,一个新的线程就产生了,通过run()方法完成操作。
常见的构造方法:
Public Thread()
Public Thread(String name)
Public Thread(Runnable target)//线程体运行所在的目标,一个实现Runnable接口对象
Public Thread(Runnable target,String name)
Java两种方法实现线程体:
1.继承线程类Thread,重写run()方法:
由于Java只支持单重继承,用这种方法定义的类不能再继承其他父类。
public class ThreadSample extends Thread {
// 线程运行状态
boolean isRunning = true;
// 计数器
int mTimer = 0;
/**
* 线程体代码
*/
@Override
public void run() {
while (isRunning) {
try {
Thread.currentThread().sleep(1000);
mTimer++;
System.out.println("逝去了 " + mTimer + " 秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception {
ThreadSample thread1 = new ThreadSample();
thread1.start();
thread1.isRunning = true;
System.out.println("计时器启动...");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
if (line.equalsIgnoreCase("1")) {
//新版本的JDK废除调用stop()
//这个方法会产生线程死锁的问题
thread1.isRunning = false;
}
br.close();
}
}
2.实现Runnable接口,并实现接口所要求的run()方法:
public class RunnableSample extends Frame implements ActionListener, Runnable {
private Label mLabel;
private Button mButton;
private Thread mClockThread;
private boolean isRunning = false;
private int mTimer = 0;
public RunnableSample() {
mButton = new Button("结束计时");
mLabel = new Label("计时器启动...");
mButton.addActionListener(this);//mButton添加事件监听器
setLayout(new BorderLayout());
add(mButton, "North");
add(mLabel, "Center");
setSize(320, 480);
setVisible(true);
//线程对象,this表示线程体当前窗口Frame对象
mClockThread = new Thread(this);
mClockThread.start(); // 启动线程
isRunning = true;
}
//Runnable接口要求实现方法
@Override
public void run() {
while (isRunning) {
try {
Thread.currentThread().sleep(1000);
mTimer++;
mLabel.setText("逝去了 " + mTimer + " 秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//按钮的单击事件处理
@Override
public void actionPerformed(ActionEvent event) {
isRunning = false;
}
//main主方法,程序入口
public static void main(String args[]) {
new RunnableSample();
}
Android中的多线程:主线程之外更新UI阻塞问题
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLabel = (TextView) findViewById(R.id.textView);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isRunning = false;
}
});
// 创建线程对象,构造方法无参数
mClockThread = new Thread() {
@Override
public void run() {
while (isRunning) {
try {
Thread.currentThread().sleep(1000);
mTimer++;
//在子线程更新UI出现错误
mLabel.setText("逝去了 " + mTimer + " 秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
mClockThread.start(); // 启动线程
}
Android的异步消息处理机制,解决主线程和子线程之间的异步通信问题。
- 在子线程进行计算、耗时处理等任务
- 完成之后将消息发送给主线程,然后主线程跟新UI
异步消息处理机制涉及的类包括:Message/MessageQueue/Handler/Looper
Message:
- 消息,可以在线程之间传递
- 可以携带参数(obj属性:可序列化对象)
MessageQueue:
- 消息队列,一个队列容器
- 一个线程一个Queue,等待处理
Handler:
- 发送新消息到消息队列里面
- 在主线程接受消息更新UI(消息处理者)
- handlerMessage()方法
Looper:
- 消息循环,每个线程只有一个Looper
- 回调dispatchMessage()
- Handler发送消息方法:send() 、post()
Send方法:
- sendEmptyMessage(int):发送一个空的消息
- sendMessage(Message):发送消息,消息可以携带参数
- sendMessageAtTime(Message,long):未来的某一时间发送消息
- sendMessageDelayed(Message,long):延时N毫秒发送消息
//接收消息
mHandler = new Handler() {
//消息到达后,回调该方法
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
mLabel.setText("逝去了 " + msg.obj + " 秒");
}
}
};
//发送消息
Message msg = new Message();
msg.obj = mTimer;
msg.what = 0;
mHandler.sendMessage(msg);
Post方法:
- post(Runnable):提交任务马上执行
- postAtTime(Runnable,long):提交任务在未来的时间点执行
- postDelayed(Runnable,long):提交任务延时N毫秒执行
Post方法本质还是发送Message对象:
mHandler = new Handler();
Runnable runnable = new Runnable(){
Public void run(){
mLabel.setText(“逝去了”+ mTimer+ “秒”);
mTimer++;
}
}
mHandler.postDelayed(runnable,1000);//发送Runnable对象