专栏首页故里学Java多线程?怎么用?

多线程?怎么用?

Java线程:概念与原理

操作系统中线程和进程的概念

现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。

线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

进程是系统进行资源分配和调度的独立单位,每一个进程都有它自己的内存空间和系统资源。进程实现多处理机环境下的进程调度,分派,切换时,都需要花费较大的时间和空间开销。为了提高系统的执行效率,减少处理机的空转时间和调度切换的时间,以及便于系统管理,所以有了线程,线程取代了进程了调度的基本功能

使用多线程最主要的原因是提高系统的资源利用率。现在CPU基本都是多核的,如果你只用单线程,那就是只用到了一个核心,其他的核心就相当于空闲在那里了

在平时工作中多线程是随时都可见的。比如说,我们系统Web服务器用的是Tomcat,Tomcat处理每一个请求都会从线程连接池里边用一个线程去处理。又比如说,我们用连接数据库会用对应的连接池,比如Druid/C3P0/DBCP等等,这些都用了多线程的。

除了上面这些框架已经帮我们屏蔽掉「手写」多线程的问题,在我本身的系统也会用到多线程的。比如说:现在要跑一个定时任务,该任务的链路执行时间和过程都非常长,我们这边就用一个线程池将该定时任务的请求进行处理,这样做的好处就是可以及时返回结果给调用方,能够提高系统的吞吐量。

在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口.(其实准确来讲,应该有三种,还有一种是实现Callable接口,并与Future、线程池结合使用,此文这里不讲这个。

Java线程的实现形式

这里继承Thread类的方法是比较常用的一种,如果说你只是想起一条线程。没有什么其它特殊的要求,那么可以使用Thread.

继承Thread类

实现Runnable接口

使用Callable和Future接口创建线程。

main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。

在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM就是在操作系统中启动了一个进程。

什么是线程安全

在我的理解下,在Java世界里边,所谓线程安全就是多个线程去执行某类,这个类始终能表现出正确的行为,那么这个类就是线程安全的。比如我有一个count变量,在service方法不断的累加这个count变量

public class UnsafeCountingServlet extends GenericServlet implements Servlet {
private long count = 0;

public long getCount() {
return count;
}

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {

++count;
// To something else...
}
}

我个人解决线程安全问题的思路有以下:

  • 能不能保证操作的原子性,考虑atomic包下的类够不够我们使用。
  • 能不能保证操作的可见性,考虑volatile关键字够不够我们使用
  • 如果涉及到对线程的控制(比如一次能使用多少个线程,当前线程触发的条件是否依赖其他线程的结果),考虑CountDownLatch/Semaphore等等。
  • 如果是集合,考虑java.util.concurrent包下的集合类。
  • 如果synchronized无法满足,考虑lock包下的类
  • ....

总的来说,就是先判断有没有线程安全问题,如果存在则根据具体的情况去判断使用什么方式去处理线程安全的问题。虽然synchronized很牛逼,但无脑使用synchronized会影响我们程序的性能的。

死锁了解吗?什么情况会造成死锁?

造成死锁的原因可以简单概括为:当前线程拥有其他线程需要的资源,当前线程等待其他线程已拥有的资源,都不放弃自己拥有的资源。避免死锁的方式一般有以下方案:

  1. 固定加锁的顺序“,比如我们可以使用Hash值的大小来确定加锁的先后
  2. 尽可能缩减加锁的范围,等到操作共享变量的时候才加锁。
  3. 使用可释放的定时锁(一段时间申请不到锁的权限了,直接释放掉)

觉得有点东西就点一下“赞和在看”吧!

本文分享自微信公众号 - 故里学Java(WLQ171223),作者:Garnett

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-09-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 性能测试工具Jmeter

    Jmeter是一款使用Java开发的开源的测试工具,主要用来做性能测试,而且用Jmeter来测试Restful API非常好用,在互联网项目开发过程中也是开发人...

    故里
  • 喂,不是吧?一个Volatile把你难住了

    Volatile可能是面试里面必问的一个话题吧,对他的认知很多朋友也仅限于会用阶段,今天我们换个角度去看看。

    故里
  • 面试 | 多线程中的上下文切换

    双十一前的一个多月,所有的电商相关的系统都在进行压测,不断的优化系统,我们的电商ERP系统也进行了一个多月的压测和优化的过程,在这其中,我们发现了大量的超时报警...

    故里
  • 40 个Java多线程问题总结

    原文地址:http://www.cnblogs.com/xrq730/p/5060921.htm

    一个优秀的废人
  • java中线程池的几种实现方式

    多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力.

    海仔
  • 100道Java并发和多线程基础面试题大集合(含解答),这波面试稳了~

    这些多线程的问题来源于各大网站,可能有些问题网上有、可能有些问题对应的答案也有、也可能有些各位网友也都看过,但是本文写作的重心就是所有的问题都会按照自己的理解回...

    程序员白楠楠
  • 线程的创建

    1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务。

    黑洞代码
  • 面试必考——线程池原理概述

    线程池的源码解析较为繁琐。各位同学必须先大体上理解线程池的核心原理后,方可进入线程池的源码分析过程。

    黑洞代码
  • 图文介绍进程和线程的区别

    先了解一下操作系统的一些相关概念,大部分操作系统(如Windows、Linux)的任务调度是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制...

    趣学程序-shaofeer
  • 笔记09 - 线程池刨根问底

    我们知道CPU运行的最小单位是线程,Java中实现并发是通过多线程来完成的,利用多线程提高了对CPU资源的利用率,但是线程的创建和销毁是很消耗性能的。线程的创建...

    码农帮派

扫码关注云+社区

领取腾讯云代金券