一、概念:
并行: 多个cpu实例或者多台机器同时执行一段处理逻辑。
并发: 并发是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。即同一个CPU交替运行多个应用程序。
线程安全: 经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果。
同步: Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。
线程: 进程中负责程序执行的执行单元线程本身依靠程序进行运行线程是程序中的顺序控制流,只能使用分配给程序的资源和环境。
进程: 执行中的程序一个进程至少包含一个线程。
单线程: 程序中只存在一个线程,实际上主方法就是一个主线程。
多线程: 在一个程序中运行多个任务目的是更好地使用CPU资源。
线程状态:
创建(new)状态: 准备好了一个多线程的对象
就绪(runnable)状态: 调用了start()方法, 等待CPU进行调度
运行(running)状态: 执行run()方法
阻塞(blocked)状态: 暂时停止执行, 可能将资源交给其它线程使用
终止(dead)状态: 线程销毁
二、线程实现
1、继承Thread类
public static void main(String[] args) {
System.out.println("主线程ID:" + Thread.currentThread().getId());
MyThread myThread = new MyThread("线程1");
myThread.start();
MyThread myThread2 = new MyThread("线程2 ");
myThread2.run();
}
static class MyThread extends Thread {
private int num = 0;
private String name;
public MyThread(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
try {
sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主动创建的第" + name + "个线程");
}
}
}
1)线程调用,run和start区别为 run会调用主线程执行,和直接写在外边没区别,而start会重新拉起一个线程执行。
2)虽然thread1的start方法调用在thread2的run方法前面调用,但是先输出的是thread2的run方法调用的相关信息,说明新线程创建的过程不会阻塞主线程的后续执行。
2、实现Runnable接口
public static void main(String[] args) {
System.out.println("主线程ID:" + Thread.currentThread().getId());
MyRunnable runnable = new MyRunnable();
Thread thread1 = new Thread(runnable);
thread1.start();
Thread thread2 = new Thread(runnable);
thread2.run();}
static class MyRunnable implements Runnable {
public MyRunnable() {
}
@Override
public void run() {
System.out.println("子线程ID:" + Thread.currentThread().getId());
}
}
样例代码:
Thread thread = new Thread(new Runnable() {
public void run() {
ServiceConfig.this.doExport();
}
});
thread.setDaemon(true);
thread.setName("DelayExportServiceThread");
thread.start();
3、线程池
为了减少创建和销毁线程的次数,让每个线程可以重复使用,可根据系统情况调整执行的线程数量,防止消耗过多内存,所以我们引进了线程池技术。一般我们业务系统中所实现的并发逻辑也推荐使用线程池实现。
现有jdk中已经包含了线程池相关的工具类,我们拿来即用即可。
代码示例(循环创建10个submit):
// 定义Future结果接收集合
List<Future<ResultModel>> resultList = new ArrayList<>();
ExecutorService liquidateExecutor = new ThreadPoolExecutor(4,2, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue(), new ParallelThreadFactory("liquidate-process"));
for (Integer i = 0; i< 10; i++) {
Future<ResultModel> future = liquidateExecutor.submit(new Callable<ResultModel>() {
@Override
public ResultModel call() {
// 线程处理逻辑
return resultModel;
}
});
resultList.add(future);
}
如上代码实际执行同时执行的线程仅有4个,前四个跑完后会拉起后面的四个,最后拉起最后两个,如此处理完十次数据。