先声明一下,本文参考了何红辉著《Android开发进阶 从小工到专家》第三章节:“Android中的多线程”内容,故逻辑可能会出现一些相似之处。
在java中,多线程使用的成本是相对较低的,其中有两种常见的使用方法:
第一种,直接重写Thread的run()方法,然后启动线程:
public class ThreadDemo {
public static void main(String[] args) {
System.out.println("主线程启动");
new Thread(){
@Override
public void run(){
System.out.println(Thread.currentThread().getName()+"正在运行");
}
}.start();
System.out.println("主线程结束");
}
}
第二种,在new Thread的时候传入一个已经实现run()方法的Runnable实例对象,Thread会执行其对应的run方法:
public class ThreadDemo {
public static void main(String[] args) {
System.out.println("主线程启动");
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"正在运行");
}
}).start();
System.out.println("主线程结束");
}
}
事实上,这两种实现方式基本上没有任何区别,因为Thread本来就是一个实现了Runnable接口的一个类(class java.lang.Thread implements java.lang.Runnable),线程最终执行的任务只是Runnable,而非Thread,Thread仅仅是对Runnable的封装。
关于线程函数:
wait():当一个线程执行此方法时,线程会释放对象锁,让其他资源可以访问对应的对象,并且此进程进入等待池中,用户可以用notify等方法来唤醒该线程。
public class ThreadDemo2 {
public static void main(String[] args) {
Object object=new Object();
System.out.println("主线程开始");
new Thread(new Runnable(){
@Override
public void run() {
synchronized (object) {
try {
Thread.sleep(2000);
object.notify();
System.out.println("唤醒主线程");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
try{
synchronized (object) {
System.out.println("主线程等待中");
object.wait();
}
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("主线程停止");
}
}
以上示例中,由于在子线程启动之后,主线程调用了object的wait()方法,使得主线程进入等待状态,等到子线程中执行objcet.notify()方法之后,主线程才会被唤醒,执行结果如下:
主线程开始
主线程等待中
唤醒主线程
主线程停止
sleep():当一个线程执行此方法时,进入睡眠状态,但不释放对象锁。这个方法理解比较简单,此处不做示例。
join():当一个线程执行此方法是,其他线程在执行在当前线程完之前不执行。
public class ThreadDemo3 {
public static void main(String[] args) {
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.start();
try {
System.out.println("启动线程1");
t1.join();
t2.start();
System.out.println("启动线程2");
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主线程执行完毕");
}
}
class MyThread extends Thread{
@Override
public void run(){
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"正在运行");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以上示例,由于t1启动之后,立刻调用了join方法,故其他线程会等待其执行完毕之后,再继续执行,同理,t2执行值后调用join方法,故主线程等待到t2执行完毕之后才继续执行。输出结果如下:
启动线程1
Thread-0正在运行
启动线程2
Thread-1正在运行
主线程执行完毕
yield():线程礼让,当前线程释放对象锁,并且让出执行权限,转换为就绪状态。
public class ThreadDemo4 {
public static void main(String[] args) {
Thread t1=new MyThread(true);
Thread t2=new MyThread(false);
t1.start();
t2.start();
}
}
class MyThread extends Thread{
private boolean isYield; //是否进行线程礼让
public MyThread(boolean yield){
isYield=yield;
}
@Override
public void run(){
for(int i=0;i<6;i++){
if(i==3&&isYield){
System.out.println(Thread.currentThread().getName()+"线程礼让");
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"\ti="+i);
}
}
}
输出结果如下:
Thread-1 i=0
Thread-0 i=0
Thread-1 i=1
Thread-0 i=1
Thread-1 i=2
Thread-0 i=2
Thread-1 i=3
Thread-0线程礼让
Thread-1 i=4
Thread-1 i=5
Thread-0 i=3
Thread-0 i=4
Thread-0 i=5
由于我们控制当i等于3的时候t1即Thread-0执行yield函数,故在上面输出的结果输出“Thread-0线程礼让”之后,并没有立刻输出“Thread-0 i=3”而是让出执行权限,进入就绪状态,t2继续执行,所以输出“Thread-1 i=4”。可以看出yield就是让出当前线程的执行权,让其他线程优先执行。