有一句话说:想写出像样的Java代码肯定会有多线程。那么小编和大家一起开启多线程的博客之旅,愿旅途我们一起享受想要的风景。
一、什么是线程
了解线程之前,我们先来看看进程。进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。
进程独自占用资源,线程可以共享资源并且创建效率高、代价小,因而提出了线程的概念。线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
线程与进程的关系:
现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。多线程,看似同时执行,在某一瞬间只做一件事情,切换的速度我们感觉不到而已;“同时”执行是人的感觉,在线程之间实际上轮换执行。
二、为什么要用线程
1.多核处理器:可以同时处理多个线程,显著减少程序处理时间。
2.更快的响应时间:
针对一些复杂的业务逻辑,这些数据不需要强一致性,可以分批给其他线程处理;
好处:响应用户请求的线程能尽快处理完成,缩短响应时间,提升用户体验。
3.更好的编程模型。
三、如何创建启动线程
一般使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。
1.扩展java.lang.Thread类,如果是扩展java.lang.Thread类的线程,则直接new即可。
更详细的步骤如下:
1)定义Thread类的子类,重写该类的run()方法,该run()方法的方法体代表了线程需要完成的任务;
2)创建Thread子类的实例,即创建了线程对象;
3)调用线程对象的 start() 方法来启动线程。
//步骤1:定义一个继承Thread类的子类:
class TestThead extends Thraad{
public void run(){
system.out.println("继承Thraad类创建线程");
}
}
//步骤2:构造子类的一个对象:
TestThread testThread = new TestThread();
//步骤3:启动线程:
testThread.start();
至此,一个线程就创建完成了。这种创建线程的方法不够好,主要是因为其涉及运行机制问题,影响程序性能。
2.实现java.lang.Runnable接口,如果是实现了java.lang.Runnable接口的类,则用Thread的构造方法:
Thread(Runnable target) ;
Thread(Runnable target, String name) ;
Thread(ThreadGroup group, Runnable target) ;
Thread(ThreadGroup group, Runnable target, String name) ;
Thread(ThreadGroup group, Runnable target, String name, long stackSize)。
创建步骤如下:
1)定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法体同样是该线程的线程执行体;
2)创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
3)调用线程对象的start()方法来启动该线程。例如:
//步骤1:创建实现Runnable接口的类:
class TestRunnable implements Runnable{
public void run(){
system.out.println("实现Runnable接口创建线程");
}
}
//步骤2:创建一个类对象:
Runnable testRunnable = new TestRunnable();
//步骤3:由Runnable创建一个Thread对象:
Thread testThread = new Thread(oneRunnable);
//步骤4:启动线程:
testThread.start();
至此,一个线程就创建完成了。线程的执行流程很简单,当执行代码oneThread.start();时,就会执行oneRunnable对象中的voidrun();方法,该方法执行完成后,线程就消亡了。
3.使用Callable和Future,创建步骤如下:
1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,且该call()方法有返回值,再创建Callable实现类的实例;
2)使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值;
3)使用FutrueTask对象作为Thread对象的target创建并启动新线程;
4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。例如:
//Callable接口(也只有一个方法)定义如下:
public interface Callable<T>{
T call() throws Exception;
}
//步骤1:创建实现Callable接口的类TestCallable<Integer>;
//步骤2:创建一个类对象:
Callable<Integer> testCallable = new TestCallable<Integer>();
//步骤3:由Callable<Integer>创建一个FutureTask<Integer>对象:
//FutureTask<Integer>是一个包装器,它通过接受Callable<Integer>来创建,它同时实现了Future和Runnable接口
FutureTask<Integer> testTask = new FutureTask<Integer>(testCallable);
//步骤4:由FutureTask<Integer>创建一个Thread对象:
Thread testThread = new Thread(testTask);
//步骤5:启动线程:
testThread.start();
至此,一个线程就创建完成了。
4.三种创建方式的比较
可见,Runnable与Callable的实现方式基本相同,只是Callable里定义的方法有返回值,且可以声明抛出异常。一般采用实现Runnable接口、Callable接口的方式来创建多线程。
一个小时为单位的话,看似只做了一件事情学习或是工作,然而这一个小时里的工作或学习可能做了多项内容,比如说:学了英语和计算机java、分析了需求与敲代码实现功能等。然而只用一个主体,只能在某一瞬间只能做一件事情,如何处理多个事情并发多线程问题,一起期待下次分享。