java 多线程
一、基础概念
1.进程:把一个任务或者应用成为一个进程,比如浏览器,QQ,微信等都是进程。
2.线程:进程中程序的执行单元,比如我们在QQ浏览空间的时候,后台还在进行聊天消息的监控,如果在浏览空间网页的同时,来了一条qq消息,那么就会弹出提示窗口。此时浏览空间和后台监控消息就是线程。
3.进程与线程之间的关系:一个进程可以包含多个线程,但至少有一个线程,是一种包含关系。同时,多个线程共享进程的资源空间。
二 创建线程的方式(两种)
1.继承Thread类
public class BlogTest {
public static void main(String[] args) {
Thread thread=new ThreadDemo();
thread.start();
}
}
class ThreadDemo extends Thread{
@Override
public void run(){
System.out.println("这是一个线程");
}
}
*通过继承Thread类,重写run方法,并在方法里面写线程的运行代码。
*调用start方法,运行线程。只要调用start方法,就会自动调用线程里的run方法。
2.实现Runnable接口
public class BlogTest {
public static void main(String[] args) {
Thread thread=new Thread(new ThreadDemo());
thread.start();
}
}
class ThreadDemo implements Runnable{
@Override
public void run(){
System.out.println("通过Runnable创建一个线程");
}
}
*通过实现Runnable接口,重写run方法,实现多线程。
*创建Thread
实例时,传入一个Runnable
实例,并调用start方法。
思考(用继承方式还是接口方式)
首先,这两种方式都可以实现多线程。主要看实际情况。比如,我们知道java不支持多重继承,一个类只能继承一个父类,然而却可以实现多个接口,那么当一个类已经继承父类的时候,如果还想使用多线程,就必须要调用Runnale接口了。
Runnable接口的缺点
利用Runnable接口实现的多线程是没有返回值的,如果任务需要一个返回结果,那么只能保存到变量,还要提供额外的方法读取,非常不便,那么就需要利用Callable 接口来实现。
public class BlogTest {
public static void main(String[] args) throws InterruptedException,ExecutionException {
//创建一个线程数为2的线程池;
ExecutorService executorService= Executors.newFixedThreadPool(2);
//定义线程任务
Callable<String> task=new ThreadDemo();
//运行 Callable 任务可以拿到一个 Future 对象,表示异步计算的结果,而线程池的submit函数返回的就是
// future对象,当我们提交一个Callable任务后,我们会同时获得一个Future对象,然后,我们在主线程某个
// 时刻调用Future对象的get()方法,就可以获得异步执行的结果。在调用get()时,如果异步任务已经完成,
// 我们就直接获得结果。如果异步任务还没有完成,那么get()会阻塞,直到任务完成后才返回结果。
Future<String> future=executorService.submit(task);
System.out.println(future.get());
}
}
class ThreadDemo implements Callable<String>{
@Override
public String call() throws Exception{
System.out.println("通过Runnable创建一个线程");
return "这是一个返回值";
}
}