JAVA线程-任务
一、创建任务
有两种方法:
(1)实现Callable接口,重写call方法。
这里的没有将任务与具体线程进行绑定。而是通过ExecutorService.submit()方法将任务提交给某个线程或是传递给FutureTask。
(2)实现Runnable接口并编写run()方法
这里的没有将任务与具体线程进行绑定。可以通过将Runnable对象提交给Thread类构造器实现任务与具体线程绑定。
public class Task implements Runnable{
//数据
……..
//方法
……..
//run()
public void run(){
……….
}
}
Thread thrd = new Thread(new Task());
thrd.start();
(3)尽管java提供了一些实现了Runable接口的类,并且可在这些类的run()方法体内可描述任务,但是,这违反了任务与线程、任务管理分离地原则,而不提倡使用。
1)Thread用于创建线程和线程的状态管理等
2)Future及其子类FutureTask用于任务的管理
3)TimerTask用于描述计时或周期的任务(这是例外)
二、从任务中产生返回值
1、使用Callable接口
Runnable接口是执行工作的独立任务,它不返回任何值。
可通过实现Callable接口并可以重写Callable接口的call()方法来实现。
Callable接口是一种具有类型参数的范型,其类型参数表示从call()中返回的类型。
并且使用ExecutorService.submit()方法调用实现Callable接口的类的对象。
例如:
public Task implements Callable<String> {
String result;
…….
public String call(){
return …+ result;
}
}
//main()
ExecutorService exec = Executors.new CachedThreadPool();
String relt = exec.submit(new Task()); // submit()返回一个范型Future对象
……..
exec.shutdown();
2、使用Future及其子类
三、执行任务
1、使用Thread类对象创建的线程执行任务
(1)实现Runnable接口
(2)调用Thread对象的start()和run()方法
2、使用执行器(Executor)(即线程池)创建的线程执行任务
(1)创建一个线程的代价有点高,因为需要与操作系统交互。而将实现Runnable的对象和实现Callable的对象提交给线程池,线程池中的线程会调用run()方法执行任务,当run()返回后,线程也不会死亡,而是在线程池中等待下一个任务。
(2)使用线程池可以减少并发线程的数量。
(3)实例
public Task implements Runnable{ ……..}
//main()
ExecutorService exec = Executors.new CachedThreadPool(); //创建线程池
exec.execute(new Task()); //提交任务
exec.shutdown(); //关闭线程池
四、任务间通信
1、使用管道实现任务间(线程间)输入/输出。
2、JAVA中对应的类为PipedWriter类(允许任务向管道写)和PipedReader类(允许不同任务从同一个管道中读取)。
3、例如:
/*发送任务*/
class Sender implements Runnable{
private Random rand = new Random(47);
private PipedWriter out = new PipedWriter(); //写入管道
public PipedWriter get PipedWriter(){return out;}// 获取写入管道对象
public void run(){
try{
while(true)
for(char c = ‘A’; c <= ‘z’; c++){
out.write(c);
TimeUnit.MILLISECONDS.sleep(rand.netInt(500));
}
}catch(IOException e){
print(e + “Sender write exception”);
}catch(InterruptedException e){
print(e + “Sender write interrupted”);
}
}
}
/*接收任务*/
class Receiver implements Runnable{
private PipedReader in; //读取管道
public Receiver(Sender sender) throws IOException{
//读取管道与指定任务的写入管道绑定
in = new PipedReader(sender.getPipedWriter());
}
public void run(){
try{
while(true){
printnb(“Read: ” + (char)in.read() + “, ”);
}
}catch(IOException e){
print(e + “Receiver read exception”);
}
}
}
//main()
Sender sender = new Sender(); //发送任务
Receiver receiver = new Receiver(sender); //接收任务
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(sender);
exec.execute(receiver);
TimeUnit.SECONDS.sleep(4);
exec.shutdownNow();
//out
Read: A, Read: B, Read: C, Read: D, Read: F, Read: G, Read: H, Read: I,
java.lang.InterruptedException: sleep interrupted Sender
sleep interrupted
java.io.InterruptedIOException Receiver read exception
六、取消任务
1、使用使用Future及其子类,这是友好的
2、使终止执行任务的线程,不确定
3、关闭线程池,这也是暴力的,不计后果的
七、线程在哪里
1、一旦创建了一个程序,就存在一个线程,即main()
2、隐式创建的线程,即使用执行器(Excutor)创建
3、显式创建的线程,即直接使用Thread类创建
|
|