线程的基本介绍:
定义:线程是操作系统能够能够进行运算调度的最小单位,它被包含在进程当中,是进程的实际运作单位。
并发和并行的介绍:
并发:在一个时间段内能运行多个线程,通过系统的调度交替执行。
并行:在某个时刻多个线程同时运行,多核cpu或者多cpu是并行的基本保证。
并发如下图:多个线程通过获得cpu的时间片来执行,但同一时刻只有一个线程在运行,多个线程在一段时间内交替执行,由于切换快,所以从外面看是同时运行。
并行如下图:在某个时刻,多个线程是同时运行的,而不是交替执行,是同时执行,这需要多核cpu和多cpu的情况下才能做到并行。
为什么需要多线程:
- 在多核cpu或者多cpu的计算机资源条件下,利用多线程可以实现真正意义上的并行执行,提高程序效率和充分利用计算机资源。
- 在一个应用进程中,会存在多个同时执行的任务,如果一个任务被阻塞,将会引起不依赖该任务的任务也被阻塞。通过对不同任务创建不同线程去处理,可以解决该问题。提高程序处理效率。
- 线程可以看作轻量级的进程,线程的创建、销毁要比进程开销要小。
线程的应用场景:
- 使用多线程实现文件下载。
- 后台任务:比如定时向大量用户发送邮件,发送短信等。
- 异步处理:记录日志等。
- 多步骤任务处理:可根据步骤特征选用不同个数和特征的线程来协助处理,多任务分割,由一个主线程分割给多个线程完成。
总结:
合理利用多核心cpu资源来实现线程的并行处理,实现同一个进程内多个任务并行执行,同时基于线程本身的异步执行特性,提升任务处理效率。
在java中使用多线程:
在java中有三种方式使用多线程:
- 创建类继承Thread类并重写run方法。调用该线程的start()方法启动线程。调用run方法不是启动线程,仅仅调用了这个方法。执行的仍然是主线程,第二种方法同理。
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
/**
* 静态内部类继承Thread类实现线程
*/
static class MyThread extends Thread{
@Override
public void run() {
System.out.println("当前执行的线程是->"+Thread.currentThread().getName());
}
}
}
执行结果:
- 创建类实现Runnable接口并实现run()方法。
public class RunnableDemo {
public static void main(String[] args) {
new Thread(new MyRunnable()).start();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("当前执行的线程是->"+Thread.currentThread().getName());
}
}
}
执行结果:
- 创建类实现Callable接口并实现call方法,这种方法需要线程池的辅助才能实现,并且使用这种方法实现的线程是可以返回结果的。
public class CallableDemo {
public static void main(String[] args) {
//这种方法需要线程池的辅助实现多线程
//这种方法实现的多线程是有返回值的。
MyCallable callable = new MyCallable();
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<String> future = executorService.submit(callable);
try {
//这是一个阻塞方法,会一直阻塞到线程执行完成返回值。
String result = future.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
static class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("当前执行的线程是->"+Thread.currentThread().getName());
return "线程执行完毕";
}
}
}
执行结果: