多线程介绍
进程和线程
进程是计算机运行的一个独立的应用程序,进程是一个动态的概念,必须是运行状态。如果一个应用程序没有启动,那就不是一个进程。
线程就是组成进程的基本单位,可以完成特定的功能,一个进程是由一个或多个线程组成。
进程和线程的区别:
1、内存空间的
区别进程是有独立空间的,在线程创建时就会分配空间(例如:堆),每个进程的空间是相互独立的,互不影响。
线程有共享的空间,也有独立的空间。
堆空间:线程共有 虚拟机栈:线程私有
2、线程安全性
进程之间是相互独立的,一个进程的崩溃不会影响其他进程,进程之间是安全的。
线程之间存在内存共享,一个线程的崩溃可能会影响到其他的线程执行,线程的安全性不如进程。
Java中很少使用到进程的概念,但也可以使用
//Runtime getRuntime() 启动一个进程 Runtime getRuntime()
线程的创建
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
实现Runnable接口
public interface Runnable{
public abstract void run();
}
Runnable接口中提供了一个run抽象方法,所有新创建的线程要执行的业务逻辑在run方法中实现
创建一个runnable接口的实现类:
public class RunTestDemo implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName()+"子线程执行业务逻辑");
}
}
通过Runnbale接口来实现线程调用:
//创建一个Runnable的任务体实例
RunTestDemo runable=new RunTestDemo();
//创建一个线程实例来执行任务体
Thread thread = new Thread(runable);
thread.setName("yk");//设置子线程名字
//启动子线程
thread.start();
通过Runnable接口来创建多线程
1、实现一个Runnable接口的实现类,在该类中将子线程的业务就在run方法中实现。
2、实例化一个Runnable的实例。
3、创建Thread类实例,将实例化的Runnable对象作为参数传递。
4、启动子线程,调用Thread对象的start方法。
继承Thread类
Thread类定义
public class Thread implements Runnable
Thread类实现了Runnable接口,即Thread类也是Runnable接口的实现类。
@Overried
public void fun(){
if(target!=null){
target.run();
}
}
在子线程汇总需要实现自定义的业务,通过继承Thread类就需要重写run方法
public class ThreadTestDemo extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"子线程正在进行");
}
}
通过继承Thread类来创建
public static void threadDemo() {
ThreadTestDemo threadTestDemo = new ThreadTestDemo();
threadTestDemo.start();
System.out.println(Thread.currentThread().getName()+"主线程执行");
}
通过继承Thread类来创建子线程步骤:
1、创建类:继承自Thread(extends Thread),重写run方法。
2、实例化自定义的Thread的子类。
3、启动子线程。
实现Callable接口
Callable接口声明形式:
public interface Callable<V>{
V call() throws Exception;
}
Callable接口提供了call方法,方法具有返回值,通过泛型类定义的,且可以抛出异常。
该接口的实现类无法直接使用,需要借助Future Task类
Future Task类声明如下:
public class FutureTask<V> implements RunnableFuture<V>
public interface RunnableFuture<V> extends Runnable,Future<V>{
void run();
}
FutureTask类是实现自RunnableFuture接口,FutureTask是可以接收Callable的接口。
RunnableFuture接口是继承自Runnable接口,意味着该FutureTask类的实例可以作为参数传递给Thread。
实现Runnable接口的实现类:
public class CallableTestDemo implements Callable<String>{
@Override
public String call() throws Exception {
String name=Thread.currentThread().getName();
System.out.println(name+"子线程正在执行");
return null;
}
创建Callable接口来创建子线程:
public static void callableDemo() {
//实例化一个Calable接口的实现类
CallableTestDemo callableTestDemo = new CallableTestDemo();
//实例化一个FuturTask实例,并传入Callable对象实例
FutureTask futureTask = new FutureTask(callableTestDemo);
//实例化Thread对象,将FutureTask实例对象传入(本质上是Runable的实例)
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(Thread.currentThread().getName()+"主线程执行");
}
通过Callable接口来创建子线程步骤:
1、实现一个Callable的实现类,实现call方法。
2、实例化一个Callable的实例对象。
3、创建一个FutureTask类型的对象实例,并传入Callable的实例对象。
4、创建Thread的实例,将FutureTask实例对象传入。
5、启动子线程。
Runnable和Thread形式创建新线程的区别?
- 线程类继承自Thread类则不能继承其他类(单继承),而Runnable接口可以实现多个接口。
- 线程类继承自Thread类相比继承自Runnable来说,使用继承Thread类的方式要相对简单。
- 实现Runnable接口的线程类的多个线程,可以方便的共享同一个变量,而Thread类需要通过传参类完成共享。
Callable和Runnable接口的区别?
- Callable接口中制定了call方法,Runnable接口中指定的是run方法。
- Callable的任务执行后可以返回值,而Runnable接口的任务是不能返回的。
- call方法可以抛出异常,run方法不能抛出异常。
- Callable接口的任务可以获取一个Future的对象,Future对象表示异步获取结果,提供了一些丰富的方法,取消任务,判断任务是否执行等等。。。
多线程的优势:
多线程作为一种多任务、并发的工作方式,当然有其存在优势:
① 进程之前不能共享内存,而线程之间共享内存(堆内存)则很简单。
② 系统创建进程时需要为该进程重新分配系统资源,创建线程则代价小很多,因此实现多任务并发时,多线程效率更高.
③ Java语言本身内置多线程功能的支持,而不是单纯第作为底层系统的调度方式,从而简化了多线程编程.