实现Callable接口
步骤和刚才演示线程池执行Runnable对象的差不多。
但是还可以更好玩一些,求和案例演示
•好处:
•可以有返回值
•可以抛出异常
•弊端:
•代码比较复杂,所以一般不用
下面是使用Callable接口实现的一个累加计算的小程序实现代码:
package cn.itcast_10;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/*
* 多线程实现的方式3:
* A:创建一个线程池对象,控制要创建几个线程对象。
* public static ExecutorService newFixedThreadPool(int nThreads)
* B:这种线程池的线程可以执行:
* 可以执行Runnable对象或者Callable对象代表的线程
* 做一个类实现Runnable接口。
* C:调用如下方法即可
* Future> submit(Runnable task)
* Future submit(Callable task)
* D:我就要结束,可以吗?
* 可以。
*/
public class CallableDemo {
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2);
// 可以执行Runnable对象或者Callable对象代表的线程
Future f1 = pool.submit(new MyCallable(100));
Future f2 = pool.submit(new MyCallable(200));
// V get()
Integer i1 = f1.get();
Integer i2 = f2.get();
System.out.println(i1);
System.out.println(i2);
// 结束
pool.shutdown();
}
}
package cn.itcast_10;
import java.util.concurrent.Callable;
/*
* 线程求和案例
*/
public class MyCallable implements Callable {
private int number;
public MyCallable(int number) {
this.number = number;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int x = 1; x <= number; x++) {
sum += x;
}
return sum;
}
}
匿名内部类方式使用多线程
new Thread(){代码…}.start();
new Thread(new Runnable(){代码…}).start();
package cn.itcast_11;
/*
* 匿名内部类的格式:
* new 类名或者接口名() {
* 重写方法;
* };
* 本质:是该类或者接口的子类对象。
*/
public class ThreadDemo {
public static void main(String[] args) {
// 继承Thread类来实现多线程
new Thread() {
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":"
+ x);
}
}
}.start();
// 实现Runnable接口来实现多线程
new Thread(new Runnable() {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + ":"
+ x);
}
}
}) {
}.start();
// 更有难度的
new Thread(new Runnable() {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println("hello" + ":" + x);
}
}
}) {
public void run() {
for (int x = 0; x < 100; x++) {
System.out.println("world" + ":" + x);
}
}
}.start();
//相当于重写了run()方法,打印word+i
}
}
定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能
Timer
•public Timer()
•public abstract void run()
•public boolean cancel()
开发中
Quartz是一个完全由java编写的开源调度框架。
使用计时器实现的一个定时删除指定文件夹的程序代码:
package 定时器删除文件夹;
import java.io.File;
import java.util.Date;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
public class TextDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
Timer timer = new Timer();
System.out.print("请输入您要删除文件的位置: ");
String FilePath = in.nextLine();
System.out.println("请输入您要删除文件的指定时间(yyyy-MM-dd-hh-mm): ");
String time = in.next();
Date date = new Date(
Integer.valueOf(time.substring(0, 4))-1900,
Integer.valueOf(time.substring(5, 7))-1,
Integer.valueOf(time.substring(8, 10)),
Integer.valueOf(time.substring(11, 13)),
Integer.valueOf(time.substring(time.lastIndexOf('-')+1))
);
System.out.println(date.toLocaleString());
timer.schedule(new TaskDemo(timer,FilePath), date);
}
}
class TaskDemo extends TimerTask {
private Timer timer = null;
private String FilePath = null;
/**
* 递归删除文件夹
* @param FilePath
*/
public void delete(String FilePath) {
File file = new File(FilePath);
if (file.exists()) {
// 删除
File[] files = file.listFiles();
for (File file2 : files) {
if (file2.isFile()) {
System.out.println("成功删除: "+file2.getName()+" "+file2.delete());
} else if (file2.isDirectory()) {
delete(file2.getPath());
}
}
file.delete();
} else {
System.out.println("您输入的文件夹/文件不存在~");
}
}
@Override
public void run() {
// TODO Auto-generated method stub
delete(FilePath);
timer.cancel();
}
public TaskDemo() {
}
public TaskDemo(Timer timer, String FilePath) {
this.timer = timer;
this.FilePath = FilePath;
}
}
运行效果:
1:多线程有几种实现方案,分别是哪几种?
两种。
继承Thread类
实现Runnable接口
扩展一种:实现Callable接口。这个得和线程池结合。
2:同步有几种方式,分别是什么?
两种。
同步代码块
同步方法
3:启动一个线程是run()还是start()?它们的区别?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start():启动线程,并由JVM自动调用run()方法
4:sleep()和wait()方法的区别
sleep():必须指时间;不释放锁。
wait():可以不指定时间,也可以指定时间;释放锁。
5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面。
6:线程的生命周期图(图解)
新建 -- 就绪 -- 运行 -- 死亡
新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡