一,简单回顾
线程的两种实现方式:
1.继承Thread类(不推荐)–其实Thread类本身就是实现了Runnable接口
public class MyThread extends Thread{
private static int i= 0;
public MyThread(){
i++;
}
@Override
public void run() {
System.out.println("创建第"+i+"个线程");
}
}
2.实现Runnable接口
public class MyThread {
public static void main(String[] args) {
System.out.println("主线程ID:" + Thread.currentThread().getId());
new Thread(new MyRunnable()).start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
// 只关心要做的任务
System.out.println("子线程ID:" + Thread.currentThread().getId());
}
}
或者直接这样:
public static void main(String[] args) {
System.out.println("主线程ID:" + Thread.currentThread().getId());
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("子线程ID:" + Thread.currentThread().getId());
}
};
new Thread(runnable).start();
}
结果都是:
主线程ID:1
子线程ID:9
二,线程状态
**- sleep,yield和wait的区别:
- sleep和yield是Thread类的静态方法,wait是Object类中定义的方法.
- Thread.sleep不会导致锁行为的改变, 如果当前线程是拥有锁的, 那么Thread.sleep不会让线程释放锁.
- wait()的作用是让当前线程由“运行状态”进入到“等待(阻塞)状态”,并释放同步锁。
- 而yield()的作用是让步,它让当前线程离开“运行状态”,进入到“就绪状态”。而且yield()方法不会释放锁。yield()只能使同优先级或更高优先级的线程有执行的机会。
- wait可以用notify/notifyAll方法唤醒,如果调用的是await,需要调用signal/signalAll来唤醒,两者只是名字不同,内部实现完全一样。**
三,使用Callable+Future/FutureTask
与Runnable不同的是,Callable**有返回结果**,其他用法一样,线程常用类都在java.util.concurrent并发包内。
public interface Callable<V> {
//此接口里只有这一个方法
V call() throws Exception;//注意到,接口的参数类型就是方法的返回类型
@Override
public Object call() throws Exception {
// 我们可以看到返回的是Object,call与run方法内部实现一样,换了名字而已
//do something...
return null;
}
FutureTask实现了RunnableFuture接口,后者又分别继承了Runnable和Future接口,在线程中,用Future来接收线程的执行结果,jdk1.7中提供了可以操作线程或者查看线程状态的5个方法,分别是cancel,isCancelled,isDone,get和get的重写。但是其有个缺点,当多线程时,并不知道哪个线程先结束,为了提高性能,便有了FutureTask。它可以准确获取线程执行完成后返回的结果,此功能得益于它有一个回调函数protected void done(),当任务结束时,该回调函数会被触发。具体做什么,可以自己重载去实现。
e.g
package com.wz.test;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
public class AboutFuture {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();//稍后分析Executors的线程池框架
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
Random random = new Random();
TimeUnit.SECONDS.sleep(random.nextInt(10));
return Thread.currentThread().getName();
}
};
for (int i = 0; i < 6; i++) {
AboutFutureTask futureTask = new AboutFutureTask(callable);
Future<?> future=executor.submit(futureTask);
System.out.println("返回结果future:" + future);//返回结果future:java.util.concurrent.FutureTask@5193b022,这里只列出一条结果
}
executor.shutdown();
}
}
class AboutFutureTask extends FutureTask<String> {
public AboutFutureTask(Callable<String> callable) {
//此处构造器是必需的
super(callable);
}
@Override
protected void done() {//重写FutureTask中的done()可以做自己想做的任务或者获取线程的信息
try {
System.out.println(get() + "当前线程已执行完毕!");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
执行结果:
pool-1-thread-2当前线程已执行完毕!
pool-1-thread-5当前线程已执行完毕!
pool-1-thread-3当前线程已执行完毕!
pool-1-thread-4当前线程已执行完毕!
pool-1-thread-1当前线程已执行完毕!
pool-1-thread-6当前线程已执行完毕!
四,Thread其他常用方法(已过时的不列举)
- public static native Thread currentThread();//返回当前运行的线程对象
public static void yield();//推荐静态调用;暂停当前线程对象,恢复到可执行状态,自己仍可以再次执行;
public final native boolean isAlive();//线程是否处于活动状态
public final void join();//让其他线程等待该线程结束
public final void join(long millis);//让其他线程等待该线程结束,最多等millis毫秒
关于线程中断:
public void interrupt() ;//向线程发出中断请求。
public static boolean interrupted() ;//测试当前线程是否被中断。值得注意的是,这是个静态方法,调用它时会产生副作用—重置当前线程的中断状态为false,也就是说如果某个线程在中断情况下,调用了此方法,会将此线程唤醒。但是换个角度,如果当notifyAll()不起作用,也就是锁标志等待池中没有任何活动线程时,可以调用该方法,激活一个线程,从而去拯救其他线程。
public boolean isInterrupted() ;//测试线程是否被终止。此调用不会改变线程状态。