1 概念
线程是应用程序调度的最小单位;每个线程有独立的运行栈和程序计数器(PC);同一类线程共享内存,共享内存使线程之间的通信比进程之间通信更有效、容易;线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
我的另一篇博客:Java进阶之详解多线程
1.1 Thread类
通过使用Thread类,我们就可以启动,停止,中断一个线程. 在同一个时间片里, 可能会有多个线程在执行, 每个线程都拥有它自己的方法调用堆栈, 参数和变量.每个app至少会有一个线程–主线程(main thread).
1.2 Runnable接口
Runnable接口可声明一连串的事务,常用于多线程处理。但是实现Runnable接口并不意味着开启了一个新线程,只是定义了要做的事情,至于说这些事情要在UI线程处理,还是在非UI线程处理,那得看我们在哪里运行Runnable实例。如果在Handler或者View中启动Runnable,那么Runnable事务便运行于UI线程;如果在Thread中启动Runnable,那么Runnable事务便运行于非UI线程。
1.2.1 采用Handler类的post方法
(1)post : 立即启动Runnable
(2)postDelayed : 延迟指定时间间隔后启动Runnable
(3)postAtTime : 在指定时间启动Runnable
(4)removeCallbacks : 回收/移除指定的Runnable
private Handler mHandler;//全局变量
@Override
protected void onCreate(Bundle savedInstanceState) {
.......
mHandler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);//在子线程有一段耗时操作,比如请求网络
mHandler.post(new Runnable() {
@Override
public void run() {
mTestTV.setText("This is post");//在主线程更新UI
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
1.2.2 使用View类的post方法
View类也提供了post和postDelayed两个方法,控件或视图可以直接调用自身的post方法,无需另外声明Handler对象。查看View的post源码,会发现其内部就是调用自身Handler实例的post方法。
1.2.3 利用Thread类构造Runnable的新线程
Thread方式启动Runnable,也只需两个步骤,第一步使用Runnable对象构造一个Thread实例,第二步启动这个Thread实例。
Thread runTread = new Thread(new Runnable() {
@Override
public void run() {
}
});
runTread.start();
1.2.4 参考链接
Android开发笔记(四十七)Runnable接口实现多线程
从Handler.post(Runnable r)再一次梳理Android的消息机制(以及handler的内存泄露)
2 创建线程方式
2.1 第一种:直接建立一个Thread子线程,并启动。
new Thread() {
@Override
public void run() {
//这里写入子线程需要做的工作
}
}.start();
// 完毕
public class ThreadDemo1 {
public static void main(String[] args){
MyThread thread = new MyThread();
thread.start();
for(int i=0;i<60;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
class MyThread extends Thread{
public void run(){
for(int i=0;i<60;i++){
System.out.println(Thread.currentThread().getName()+i);
}
}
}
2.2 第二种:建立一个Thread子线程,实现Runnable接口,然后启动。
//声明一个子线程
private Thread newThread = new Thread(new Runnable() {
@Override
public void run() {
//这里写入子线程需要做的工作
}
});
newThread.start(); //启动线程
public class ThreadDemo2 {
public static void main(String[] args){
MyRunnable runnable =new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
for(int x=0;x<60;x++){
System.out.println(Thread.currentThread().getName()+x);
}
}
}
class MyRunnable implements Runnable{
public void run(){
for(int x=0;x<60;x++){
System.out.println(Thread.currentThread().getName()+x);
}
}
}
2.3 以上两种实现方式的区别和联系
(1)在程序开发中只要是多线程肯定永远以**“建立一个Thread子线程,实现Runnable接口,然后启动**”为主,因为实现Runnable接口相比继承Thread类有如下好处:
- Runnable接口实质是共享代码,类似于函数调用,但又比函数调用灵活,因为Runnable可选择实际调用的时机,而不必像函数调用那样还得等待调用结束;
- 可以避免Java单继承方式的局限。如果一个新类继承了Thread类,就不能再继承别的类。但是Runnable只是接口,所以新类可以继承别的类,同时实现Runnable接口。
(2)Runnable接口和Thread之间的联系:Thread类也是Runnable接口的子类 。
public class Thread extends Object implements Runnable
2.4 常用方法
// 取得线程名称
getName();
// 取得当前线程对象
curentThread()
// 挂起和唤醒线程
public void resume( );
// 得到线程状态,是否启动
publicboolean isAlive( );
// 线程睡眠,(Thread.sleep(1000))
public static void sleep(long millis);
public static void sleep(long millis, int nanos);
// 线程强行加入
publicvoid join( ) throws InterruptedException;
3 线程的生命周期
线程同样要经历“开始(等待)、运行、阻塞和停止”四种不同的状态。这四种状态都可以通过Thread类中的方法进行控制。
// 开始
publicvoid start( );
// 运行
publicvoid run( );
// 阻塞
// 停止线程
publicvoid stop( );
4 以卖票程序为例
(1)通过Thread类完成
class MyThread extends Thread{
private int ticket=10;
public void run(){
for(int i=0;i<20;i++){
if(this.ticket>0){
System.out.println("卖票:ticket"+this.ticket--);
}
}
}
};
/**
* 每个线程都各卖了10张,共卖了30张票,但实际只有10张票,
* 每个线程都卖自己的票,没有达到资源共享
*/
public class ThreadTicket {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
MyThread mt3 = new MyThread();
mt1.start();
mt2.start();
mt3.start();
}
}
(2)通过Runnable方法完成
class MyTask implements Runnable{
private int ticket=10;
public void run(){
for(int i=0;i<20;i++){
if(this.ticket>0){
System.out.println("卖票:ticket"+this.ticket--);
}
}
}
}
/**
* 三个线程使用同一个Runnable--task,一共卖了10张票,
* 说明使用Runnable实现多 线程达到资源共享目的。
*/
public class RunnableTicket {
public static void main(String[] args) {
MyTask task = new MyTask();
new Thread(task).start();
new Thread(task).start();//
new Thread(task).start();
}
};