一、 实现Runnable 接口,并实现该接口的 run() 方法。
- 通过实现Runnable接口的类,就是产生一个任务或者工作类,交给一个或者多个线程去完成这个任务(new Thread(任务).start()).
- 资源共享
- start()方法是一个 native(本地)方法,它将启动一个新线程,并执行 run()方法
public class ThreadTask implements Runnable {
private int ticket = 10;
public void run() {
for (int i = 0; i < 10; i++) {
if (this.ticket > 0) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + "---卖票:ticket:" + (ticket--));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ThreadTask thread = new ThreadTask();
new Thread(thread, "线程1").start();
new Thread(thread, "线程2").start();
}
}
线程2---卖票:ticket:10
线程1---卖票:ticket:9
线程1---卖票:ticket:8
线程2---卖票:ticket:7
线程2---卖票:ticket:6
线程1---卖票:ticket:5
线程1---卖票:ticket:4
线程2---卖票:ticket:3
线程1---卖票:ticket:2
线程2---卖票:ticket:1
线程1---卖票:ticket:0
二、 继承 Thread 类,重写 run 方法
public class ThreadTask extends Thread {
private int ticket = 10;
public void run() {
for (int i = 0; i < 10; i++) {
if (this.ticket > 0) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + "---卖票:ticket:" + (ticket--));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ThreadTask task = new ThreadTask();
new Thread(task,"线程1").start();
new Thread(task,"线程2").start();
}
}
Thread-1---卖票:ticket:10
Thread-0---卖票:ticket:10
Thread-1---卖票:ticket:9
Thread-0---卖票:ticket:9
Thread-1---卖票:ticket:8
Thread-0---卖票:ticket:8
Thread-1---卖票:ticket:7
Thread-0---卖票:ticket:7
Thread-1---卖票:ticket:6
Thread-0---卖票:ticket:6
Thread-1---卖票:ticket:5
Thread-0---卖票:ticket:5
Thread-0---卖票:ticket:4
Thread-1---卖票:ticket:4
Thread-1---卖票:ticket:3
Thread-0---卖票:ticket:3
Thread-1---卖票:ticket:2
Thread-0---卖票:ticket:2
Thread-1---卖票:ticket:1
Thread-0---卖票:ticket:1
- 前面这两种方式,当遇到运行时异常(非受检异常, RuntimeException)时,会导致子线程被JVM杀死 子线程结束,但不会影响到主线程。
- 主线程通过setUncaughtExceptionHandler(Thread.UncaughtExceptionHandlereh)方法用来获取线程中产生的异常.
import java.lang.Thread.UncaughtExceptionHandler;
public class ThreadTest1 {
public static void main(String[] args) {
MyThread my = new MyThread();
my.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + " : " + e.getMessage());
}
});
try {
my.start();
} catch (Exception e) {
System.out.println("error");
}
}
public static class MyThread extends Thread {
public MyThread() {}
public void run() {
for (int i = 4; i >= 0; i--) {
TimeUnit.SECONDS.sleep(1);
// 当i=0时候抛出的非受检异常,将导致当前线程被JVM杀死
System.out.println(12 / i);
}
}
}
三、 实现Callable<T>,重写call()方法。
- 异步执行,Future 对象表示异步计算的结果;当调用 Future 的 get()方法以获取结果时,当前线程就会阻塞,直到 call()方法结束返回结果。
- 运行Callable任务可拿到一个Future对象, Future表示异步计算的结果。
- 可通过FutureTask或者ExecutorServor包装
- call()方法可抛出异常,而run()方法是不能抛出异常的
- 在提交任务时,用户实现的Callable实例task会被包装为FutureTask实例ftask;提交后任务异步执行,无需用户关心;当用户需要时,再调用FutureTask#get()获取结果——或异常。
1. 通过FutureTask包装器来创建Thread线程
public class ThreadByCallable implements Callable<Integer> {
@Override
public Integer call() {
System.out.println("当前线程名称是:" + Thread.currentThread().getName());
int i = 0;
for (; i < 5; i++) {
System.out.println("循环变量i的值:" + i);
}
// call()方法有返回值
return i;
}
public static void main(String[] args) {
ThreadByCallable rt = new ThreadByCallable();
// 使用FutureTask来包装Callable对象
FutureTask<Integer> task = new FutureTask<Integer>(rt);
new Thread(task, "有返回值的线程").start();
try {
// 获取线程返回值
System.out.println("子线程的返回值:" + task.get());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
2. 通过线程池
public class CallableAndFuture {
public static class CallableTest implements Callable<String> {
public String call() throws Exception {
return "Hello World!";
}
}
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
Future<String> future = threadPool.submit(new CallableTest());
try {
System.out.println("waiting thread to finish");
System.out.println(future.get()); //等待线程结束,并获取返回结果
} catch (Exception e) {
e.printStackTrace();
}
}
}