最近又学到了很多新知识,感谢优锐课老师细致地讲解,这篇博客记录下自己所学所想,也和大家分享、了解有关Java中的并发问题和线程限制的更多信息。

在此文中,我们将探讨线程限制,它的含义以及如何实现。因此,让我们直接研究它。

线程限制

大多数并发问题仅在我们希望在线程之间共享可变变量或可变状态时才会发生。如果在多个线程之间共享了可变状态,则所有线程都将能够读取和修改状态的值,从而导致错误或意外的行为。避免此问题的一种方法是根本不共享线程之间的数据。该技术被称为线程限制,是在我们的应用程序中实现线程安全的最简单方法之一。

Java语言本身没有任何执行线程限制的方法。线程限制是通过设计程序的方式实现的,该程序不允许状态被多个线程使用,因此由实现来强制执行。线程限制有几种类型,如下所述。

临时线程限制

临时线程限制描述了一种线程限制方式,由开发人员或负责该程序的一组开发人员共同负责,以确保对象的使用仅限于单个线程。这种方法非常脆弱,在大多数情况下应避免使用。

Ad-hoc线程限制下的一种特殊情况适用于volatile变量。只要确保只从单个线程写入volatile变量,就可以对共享的volatile变量执行读-修改-写操作。在这种情况下,你将修改限制在单个线程中,以防止出现竞争情况,并且易失变量的可见性保证可确保其他线程看到最新的值。

堆栈限制

堆栈限制是将变量或对象限制在线程的堆栈中。这比临时线程约束要强得多,因为通过定义堆栈本身中变量的状态,它甚至进一步限制了对象的范围。例如,考虑以下代码:

 private long numberOfPeopleNamedJohn(List<Person> people) {
List<Person> localPeople = new ArrayList<>();
localPeople.addAll(people);
return localPeople.stream().filter(person -> person.getFirstName().equals("John")).count();
}

在上面的代码中,我们传递了一个人员列表,但没有直接使用它。 相反,我们创建自己的列表,该列表位于当前正在执行的线程的本地,并将所有人员添加到localPeople中。由于我们仅在numberOfPeopleNamedJohn方法中定义列表,因此这使变量localPeople堆栈受到限制,因为它存在于一个线程的堆栈中,因此无法被其他任何线程访问。这使localPeople线程安全。我们唯一需要注意的是,我们不应该允许localPeople逃脱此方法的范围,以使其保持在堆栈限制内。定义此变量时,也应记录或注释该变量,通常来说,只有当前的开发人员才能避免使用此变量,将来,另一位开发人员可能会搞砸了。

线程本地

ThreadLocal允许你将每个线程的值与值持有对象相关联。它允许你为不同的线程存储不同的对象,并维护哪个对象对应于哪个线程。它具有set和get访问器方法,该方法为使用它的每个线程维护该值的单独副本。get()方法始终返回从当前正在执行的线程传递给set()的最新值。让我们看一个例子:

 public class ThreadConfinementUsingThreadLocal {
public static void main(String[] args) {
ThreadLocal<String> stringHolder = new ThreadLocal<>();
Runnable runnable1 = () -> {
stringHolder.set("Thread in runnable1");
try {
Thread.sleep(5000);
System.out.println(stringHolder.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable runnable2 = () -> {
stringHolder.set("Thread in runnable2");
try {
Thread.sleep(2000);
stringHolder.set("string in runnable2 changed");
Thread.sleep(2000);
System.out.println(stringHolder.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable runnable3 = () -> {
stringHolder.set("Thread in runnable3");
try {
Thread.sleep(5000);
System.out.println(stringHolder.get());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread thread1 = new Thread(runnable1);
Thread thread2 = new Thread(runnable2);
Thread thread3 = new Thread(runnable3);
thread1.start();
thread2.start();
thread3.start();
}
}

在上面的示例中,我们使用相同的ThreadLocal对象stringHolder执行了三个线程。如你在这里看到的,首先,我们在stringHolder对象的每个线程中设置一个字符串,使其包含三个字符串。然后,经过一些暂停后,我们仅从第二个线程更改了该值。下面是程序的输出:

 string in runnable2 changed
Thread in runnable1
Thread in runnable3

如你在上面的输出中看到的,线程2的字符串已更改,但线程1和线程3的字符串未受影响。如果在从ThreadLocal获取特定线程上的值之前未设置任何值,则它将返回null。终止线程后,ThreadLocal中特定于线程的对象将准备进行垃圾回收。

这就是关于线程限制的全部内容。我希望这篇博客能对你有所帮助,并且你必须学习新的知识。

谢谢,祝你愉快!

Java并发:线程限制的更多相关文章

  1. Java 并发 线程同步

    Java 并发 线程同步 @author ixenos 同步 1.异步线程本身包含了执行时需要的数据和方法,不需要外部提供的资源和方法,在执行时也不关心与其并发执行的其他线程的状态和行为 2.然而,大 ...

  2. Java 并发 线程的优先级

    Java 并发 线程的优先级 @author ixenos 低优先级线程的执行时刻 1.在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止.退出或者由于 ...

  3. Java 并发 线程属性

    Java 并发 线程属性 @author ixenos 线程优先级 1.每当线程调度器有机会选择新线程时,首先选择具有较高优先级的线程 2.默认情况下,一个线程继承它的父线程的优先级 当在一个运行的线 ...

  4. Java 并发 线程的生命周期

    Java 并发 线程的生命周期 @author ixenos 线程的生命周期 线程状态: a)     New 新建 b)     Runnable 可运行 c)     Running 运行 (调用 ...

  5. Java并发——线程安全、线程同步、线程通信

    线程安全 进程间"共享"对象 多个“写”线程同时访问对象. 例:Timer实例的num成员,即add()方法是用的次数.即Timer实例是资源对象. class TestSync ...

  6. 从JDK源码角度看java并发线程的中断

    线程的定义给我们提供了并发执行多个任务的方式,大多数情况下我们会让每个任务都自行执行结束,这样能保证事务的一致性,但是有时我们希望在任务执行中取消任务,使线程停止.在java中要让线程安全.快速.可靠 ...

  7. Java并发——线程介绍

    前言: 互联网时代已经发展到了现在.从以前只考虑小流量到现在不得不去考虑高并发的问题.扯到了高并发的问题就要扯到线程的问题.你是否问过自己,你真正了解线程吗?还是你只知道一些其他博客里写的使用方法.下 ...

  8. java并发线程池---了解ThreadPoolExecutor就够了

    总结:线程池的特点是,在线程的数量=corePoolSize后,仅任务队列满了之后,才会从任务队列中取出一个任务,然后构造一个新的线程,循环往复直到线程数量达到maximumPoolSize执行拒绝策 ...

  9. java 并发——线程

    一.前言 前一篇文章总结了对 java 并发中的内置锁的理解,这篇文章来说说线程 ,并发与线程总有剪不断理还乱的关系.关于 java 线程的基本概念.线程与进程的关系以及如何创建线程,想必大家都很清楚 ...

  10. Java并发--线程池的使用

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

随机推荐

  1. [深度学习][图像处理][毕设][笔记][安装环境][下载地址]安装VS2013、matconvnet、cuda、cudnn过程中产生的一些记录,2018.5.6号

    最近半个多月,被cuda等软件折磨的死去活来,昨天下午,终于安装好了环境,趁着matlab正在,在线下载VOT2016数据集,3点睡眼惺忪被闹醒后,睡不着,爬上来写这份记录. 先记录一下自己电脑的基本 ...

  2. 基于R数据分析之常用Package讲解系列--1. data.table

    利用data.table包变形数据 一. 基础概念 data.table 这种数据结构相较于R中本源的data.frame 在数据处理上有运算速度更快,内存运用更高效,可认为它是data.frame ...

  3. poj 1001 求高精度幂(Java, BigDecimal, pow, hasNext, stripTrailingZeros, toPlainString)

    求高精度幂 Time Limit: 500MS   Memory Limit: 10000K Total Submissions: 180325   Accepted: 43460 Descripti ...

  4. Java开发者入职必备条件

    01.基础技术体系 我认为知识技能体系化是判断技术是否过关的第一步.知识体系化包含两层含义: 1. 能够知道技术知识图谱(高清版图谱扫文末二维码)的内容 比如分布式系统中常用的RPC技术,其背后就涉及 ...

  5. jQuery—— 选择器汇总

    jQuery里的选择器有3种: 元素选择器,id选择器, 类选择器:   $("div") // 选择所有<div>元素 $("#test") // ...

  6. Elasticsearch系列---常见搜索方式与聚合分析

    概要 本篇主要介绍常见的6种搜索方式.聚合分析语法,基本是上机实战,可以和关系型数据库作对比,如果之前了解关系型数据库,那本篇只需要了解搜索和聚合的语法规则就可以了. 搜索响应报文 以上篇建立的mus ...

  7. 看淡生死,不服就干(C语言指针)

    看淡生死,不服就干 emmmmm 其实今天蛮烦的 高等数学考的一塌糊涂 会的不会的都没写 真心没有高中轻松了啊 也不知道自己立的flag还能不能实现 既然选择了就一定坚持下去啊 下面还是放一段之前写的 ...

  8. Vue_声明周期

    Vue生命周期 在vue2.0的时候,声明钩子发生了改变,具体有八个 <!-- HTML部分 --> <div id="app"> <div>{ ...

  9. 攻克数通,斩获云计算!誉天Double HCIE学员考证秘笈揭晓

    不知不觉,已经过了四个月的时间了,我是六月多报名云计算的,本来是奔着邹Sir去的,但是当时邹sir已经上到HCIE的课程了,只能蹭学弟之前的录屏看.等到七月八号,又正式跟了曾曦老师上了一次完整的课程. ...

  10. vue—自定义指令

    今日分享—自定义指令 需要学习的点: modifiers属性的具体实例就是v-on:click.stop=”handClick” 一样,为指令添加一个修饰符. 全局指令:新建一个newDir.js i ...