java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java中的线程

浅谈Java并发编程中的线程

作者:刘婉晴

这篇文章主要介绍了浅谈Java并发编程中的线程,操作系统运行一个程序,就会创建一个进程,在一个进程里可以创建多个线程,因此线程也叫做轻量级进程,需要的朋友可以参考下

一、线程

线程是操作系统调度的最小单元,多线程同时执行,可以提高程序性能 。

1. 什么是线程

操作系统运行一个程序,就会创建一个进程,在一个进程里可以创建多个线程,因此线程也叫做轻量级进程 。

2. 线程带来了什么好处

现代处理器都是多核的,程序运行过程中能够创建多个线程,而一个线程在一个时刻只能运行在一个处理器核心上,如果一个单线程程序在运行时只能使用一个处理器核心,那么再多的处理器核心加入也无法显著提升该程序的执行效率。

3. 线程基础

(1)优先级 —— setPriority(int)

线程优先级决定线程需要多或者少分配一些处理器资源的线程属性

设置线程优先级时,针对频繁阻塞(休眠或者I/O操作)的线程需要设置较高优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。

程序正确性不能依赖于优先级高低 —— 不同操作系统有不同的处理方式

(2)状态

New 初始态\ Running 运行态 \ Blocked 阻塞态 \Waiting 等待态\ TimeWaiting 超时等待态\ Terminated 终止态

注: Java将操作系统中的运行和就绪两个状态合并称为运行状态

阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态,但是阻塞在java.concurrent包中Lock接口的线程状态却是等待状态,因为java.concurrent包中Lock接口对于阻塞的实现均使用了LockSupport类中的相关方法。

(3)Daemon 线程 —— setDaemon(true)

支持型线程,用作程序中台调度以及支持性工作 当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出

(4)线程的启动和终止

新构造的线程对象是由其parent线程来进行空间分配的,child线程继承了parent是否为Daemon、优先级和加载资源的contextClassLoader以及可继承的ThreadLocal,同时还会分配一个唯一的ID来标识这个child线程,至此,一个能够运行的线程对象就初始化好了。

start()方法的含义是:当前线程(即parent线程)同步告知Java虚拟机,只要线程规划器空闲,应立即启动调用start()方法的线程

(5)中断

Thread.currentThread().isInterrupted()

4. volatile和synchronized关键字

volatile

告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。

synchronized

关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

本质是对一个对象的监视器(monitor)进行获取,而这个获取过程是排他的,也就是同一时刻只能有一个线程获取到由synchronized所保护对象的监视器

任意一个对象都拥有自己的监视器,当这个对象由同步块或者这个对象的同步方法调用时,执行方法的线程必须先获取到该对象的监视器才能进入同步块或者同步方法,而没有获取到监视器(执行该方法)的线程将会被阻塞在同步块和同步方法的入口处,进入BLOCKED状态。

5. 等待通知

等待/通知机制是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。

等待/通知的相关方法是任意Java对象都具备的,因为这些方法被定义在所有对象的超类java.lang.Object上。

synchronized(对象) {
       while(条件不满足) {
            对象.wait();
       }
       对应的处理逻辑
}
synchronized(对象) {
       改变条件
       对象.notifyAll();
}

(1)Thread.join()

线程A执行了thread.join()语句,其含义是:当前线程A等待thread线程终止之后才从thread.join()返回

join() 当线程终止时,会调用线程自身的notifyAll()方法,会通知所有等待在该线程对象上的线程。

(2)ThreadLocal

以ThreadLocal对象为键、任意对象为值的存储结构,一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。

ThreadLocal 调用耗时统计的功能上,在方法的入口前执行begin()方法,在方法调用后执行end()方法,好处是两个方法的调用不用在一个方法或者类中,比如在AOP(面向方面编程)中,可以在方法调用前的切入点执行begin()方法,而在方法调用后的切入点执行end()方法,这样依旧可以获得方法的执行耗时。

6. 如何实现等待超时模式

场景:调用一个方法时等待一段时间0,如果该方法能够在给定的时间段之内得到结果,那么将结果立刻返回,反之,超时返回默认结果 。

解决:对象加锁 条件循环 处理逻辑 + 设置超时时间段

应用:超时等待模式可以用来实现 数据库连接池 中数据库连接操作超时返回

好处: 保证客户端线程不会一直挂在连接获取的操作上,而是“按时”返回,并告知客户端连接获取出现问题,是系统的一种自我保护机制,针对昂贵资源(比如数据库连接)的获取都应该加以超时限制。

7. 线程池

为什么需要考虑 C/S 架构的程序,如果没有线程池, 我们客户端向服务器发的请求,每个请求创建一个线程,假设我们有 1 万个请求, 那么就需要创建 1 万的线程进行处理。 众所周知,线程的创建和上下文切换是非常消耗资源的。因此, 需要线程池技术解决这个问题 。

线程池好处

线程池的默认实现

使用一个线程安全的工作队列连接工作者线程和客户端线程。

线程池种类

newSingleThreadExecutor newFixedThreadPool newCachedThreadPool : 提高执行许多短暂的异步任务的程序的性能

线程池应用:

简单的 Web 服务器 常用的Java Web服务器,如Tomcat、Jetty,在其处理请求的过程中都使用到了线程池技术。

因为我们不能一个一个请求的顺序处理,这样的话,估计就没有用户会想用了 。现代的浏览器可以并发发送多个请求, 服务器可以并发处理多个请求 。

线程池中线程数量设置

线程池中线程数量并不是越多越好,具体的数量需要评估每个任务的处理时间,以及当前计算机的处理器能力和数量。使用的线程过少,无法发挥处理器的性能;使用的线程过多,将会增加系统的无故开销,起到相反的作用。

((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

线程池可能出现的问题

到此这篇关于浅谈Java并发编程中的线程的文章就介绍到这了,更多相关Java中的线程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文