1.并行和并发的区别?
并行和并发是两个与多任务处理相关的概念,它们描述了不同的执行方式:
-
并行(Parallel):并行指的是同时执行多个任务,每个任务都在不同的处理器核心或计算单元上进行。在并行处理中,多个任务可以真正同时进行,通过利用多核处理器或分布式系统的优势,可以大大提高任务的执行效率。
-
并发(Concurrent):并发指的是多个任务按照一定的调度顺序交替执行,每个任务在时间上可能不会完全重叠。在并发处理中,虽然任务的执行是交替的,但从整体上看,这些任务似乎同时进行,因为它们在小时间片内迅速切换。并发处理常用于单核处理器或多任务操作系统中,通过快速切换和调度来实现多个任务之间的并发执行。
简而言之,关键区别在于是否可以同时执行多个任务,并行可以真正同时执行多个任务,而并发则是通过快速切换和调度使多个任务看起来同时执行。
需要注意的是,并行和并发的概念也可以应用于其他领域,不仅限于多任务处理,例如并行计算和并发编程。
2.Redis都有哪几种部署方式?
-
单机部署:即将Redis部署在单个服务器上。这种部署方式简单、适用于小规模应用场景,可以在服务器上直接运行Redis进程,也可以将Redis运行在容器中。
-
主从复制:通过将Redis实例拆分成主节点和从节点,将数据副本复制到多个从节点,实现读写分离和数据冗余备份。主从复制可以提高Redis的性能并提供数据持久化能力。
-
集群部署:Redis集群是一种分布式部署方式,可以将大量数据分散在多个节点上,提高Redis的性能和可伸缩性。Redis集群通常采用分片的方式将数据分散到不同的节点上,并使用一定的算法保证数据的一致性。
-
哨兵部署:Redis Sentinel是Redis官方提供的高可用性解决方案,可以自动检测Redis主节点的故障并将其切换到备用节点上,从而实现Redis的高可用性。Redis Sentinel由多个Sentinel节点组成,每个Sentinel节点都可以监控多个Redis主从节点。
以上是Redis的主要部署方式,在实际应用中,根据业务需求以及性能和可靠性要求等因素选择合适的部署方式非常重要。例如,在大规模高并发场景下,可能需要采用Redis集群来保证性能和可伸缩性;而在对可靠性要求较高的应用场景下,可能需要采用Redis Sentinel来实现高可用性。
3.创建线程有哪几种方式?推荐使用哪种?
在 Java 中,线程的创建方法有 7 种,分为以下 3 大类:
- 继承 Thread 类的方式,它有 2 种实现方法。
- 实现 Runnable 接口的方式,它有 3 种实现方法。
- 实现 Callable 接口的方式,它有 2 种实现方法。
接下来我们一个一个来看。
1.继承Thread类
继承 Thread 类并重写 run 方法,是最早期创建线程的方法,它的实现方法有以下两种:
- 创建一个普通的类,继承 Thread 类,并重写 run 方法。
- 使用匿名内部类的方式继承并重写 run 方法。
具体实现如下。
1.1 普通类继承Thread
创建一个普通类,继承 Thread 并重写 run 方法,其中 run 方法中的代码是线程具体要执行的业务代码,实现如下:
1.2 匿名内部类
上面的写法有点繁琐,我们还可以使用以下匿名类的方式来实现:
1.3 缺点分析
继承 Thread 类的实现方法有一个明显的缺点,Java 语言是单继承的,所以如果继承了 Thread 类,那就不能再继承其他类了。
2.实现Runnable接口
在 Java 语言中,虽然不能多继承,但可以实现多个接口。接下来是实现 Runnable 接口的 3 种方法:
- 创建一个普通类实现 Runnable 接口,并重写 run 方法。
- 使用匿名方式创建 Runnable 实现类,并重写 run 方法。
- 使用 Lambda 方式创建匿名 Runnable 实现类(JDK 8+)。
2.1 普通类实现Runnable
2.2 匿名Runnable实现类
2.3 Lambda创建Runnable
在 JDK 8 之后(包含 JDK 8),我们可以使用 Lambda 表达式来创建线程,如下代码所示:
从上述代码可以看出,如果是 JDK 1.8 以上的程序,在不要求获得线程执行结果的情况下,推荐使用 Lambda 的方式来创建线程,因为它的写法足够简洁。
2.4 缺点分析
以上创建线程的方法,都有一个通用的问题:那就是不能获得线程的执行结果。
3.使用Callable接口
JDK 1.5 中推出的 Callable 接口,解决了之前不能获得线程执行结果的尴尬,它的实现方法有以下两种:
- 创建一个普通类实现 Callable 接口,并重写 call 方法。
- 使用匿名内部类创建 Callable 的实现类,并重写 call 方法。
3.1 普通类实现Callable
以上代码使用 FutureTask + Callable 的方式获取线程的执行结果,它可以接受任何类型的返回值,我们只需要在创建 Callable 实现类的时候,定义返回的数据类型即可。
3.2 匿名Callable实现类
总结
在 Java 语言中,创建线程有 3 大类实现方式、7 种实现方法,如果是 JDK 1.8 以上版本,在不需要获得线程执行结果的情况下,推荐使用 Lambda 方式来创建线程,因为它的写法足够简洁;如果想要获取线程执行结果,可使用 FutureTask + Callable 的方式来实现。