线程

并发2-Synchronized

爷,独闯天下 提交于 2020-03-30 12:52:55
一、Synchronized的概念 是利用锁的机制来实现同步的。 锁机制有如下两种特性: 互斥性: 即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。 可见性: 必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。 二、Synchronized的使用 修饰静态方法    //修饰静态方法 public static synchronized void print() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"runing"); }    修饰非静态方法    //修饰非静态方法 public synchronized void print1() { try { TimeUnit.SECONDS.sleep(1

多线程中volatile关键字的作用

随声附和 提交于 2020-03-30 12:49:08
原文链接: https://blog.csdn.net/xuwentao37x/article/details/27804169 多线程的程序是出了名的难编写、难验证、难调试、难维护,这通常是件苦差事。不正确的多线程程序可能可以运行很多年也不出一点错,直到满足某些临界的条件时,才出现意想不到的奇怪错误。 不用说,编写多线程程序的程序员需要使用可能得到的所有帮助。这期专栏将专注于讨论竞争条件(race conditions)——这通常是多线程程序中各种麻烦的根源——深入了解它并提供一些工具来防止竞争。令人惊异的是,我们将让编译器尽其所能来帮助你做这些事。 仅仅一个不起眼的关键字。 尽管C和C++标准对于线程都明显的“保持沉默”,但它们以volatile关键字的形式,确实为多线程保留了一点特权。 就象大家更熟悉的const一样,volatile是一个类型修饰符(type modifier) 。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。下面我们来一个个说明。 考虑下面的代码: 代码: class Gadget { public: void Wait() { while (!flag_) { Sleep(1000); // sleeps for 1000 milliseconds }

java内存模型与多线程

我们两清 提交于 2020-03-30 12:48:42
现代计算机,cpu在计算的时候,并不总是从内存读取数据,它的数据读取顺序优先级是:寄存器-高速缓存-内存,线程计算的时候,原始的数据来自内存,在 计算过程中,有些数据可能被频繁读取,这些数据被存储在寄存器和高速缓存中,当线程计算完后,这些缓存的数据在适当的时候应该写回内存,当多个线程同时读 写某个内存数据时,由于涉及数据的可见性、操作的有序性,所以就会产生多线程并发问题。 Java作为平台无关性语言,JLS(Java语言规范)定义了一个统一的内存管理模型 JMM (Java Memory Model),JMM屏蔽了底层平台内存管理细节,在多线程环境中必须解决可见性和有序性的问题。JMM规定了jvm有 主内存 (Main Memory)和 工作内存 (Working Memory) ,主内存存放程序中所有的类实例、静态数据等变量,是多个线程共享的,而工作内存存放的是该线程从主内存中拷贝过来的变量以及访问方法所取得的局部变量, 是每个线程私有的其他线程不能访问,每个线程对变量的操作都是以先从主内存将其拷贝到工作内存再对其进行操作的方式进行,多个线程之间不能直接互相传递数 据通信,只能通过共享变量来进行。 JLS定义了线程对主存的操作指令: read,load,use,assign,store,write 。这些行为是不可分解的原子操作,在使用上相互依赖,read

Java集合框架(List,Set,Map)

♀尐吖头ヾ 提交于 2020-03-30 12:08:51
单列集合基本框架 List接口特点: 1. 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。 2. 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。 3. 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。 4.List 接口提供了特殊的迭代器,称为 ListIterator ,除了允许 Iterator 接口提供的正常操作外,该迭代器还允许元素插入和替换,以及双向访问。还提供了一个方法来获取从列表中指定位置开始的列表迭代器。 List接口常用实现类: ## vector集合 Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。 由 Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的 特点:1.线程同步的2.底层是数组实现的 特有方法 Enumeration<E> elements() ##ArrayList集合 1.底层是数组实现的 2.不是线程同步的 3.查询比较快 java.util.ArrayList`集合数据存储的结构是数组结构。方便元素随机访问。 ## LinkedList集合 1.底层是一个链表实现的 2.不同步。线程不安全 3

Java并发编程的艺术(六)happens-before

自闭症网瘾萝莉.ら 提交于 2020-03-30 11:53:14
1、happens-before是JMM最核心的概念,JSR-133使用happens-before来指定 两个操作之间的执行顺序 。 2、如果A happens-before B,那么: (1)对程序员来说:A的执行结果对B可见,并且A的执行顺序排在B之前。 (2)对编译器和处理器来说:不一定要按照程序顺序执行,在不改变程序执行结果(指 单线程 或 正确同步的多线程 )的前提下,允许重排序。 3、happens-before规则: (1) 程序顺序 规则:一个线程中的每个操作,happens-before于该线程中的任意后续操作。 (2) 监视器 规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。 (3) volatile变量 规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。 (4) 传递性 :如果A happens-before B,且B happens-before C,那么A happens-before C。 (5)start()规则:如果线程A执行操作ThreadB.start()(启动线程B),那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作。 (6)join()规则:如果线程A执行操作ThreadB.join()并成功返回

Delphi管理多线程之线程局部存储:threadvar

拜拜、爱过 提交于 2020-03-30 11:43:47
  尽管多线程能够解决许多问题,但是同时它又给我们带来了很多的问题。其中主要的问题就是:对全局变量或句柄这样的全局资源如何访问?另外,当必须确保一个线程中的某些事件要在另一个线程中的其他时间之前(或之后)发生时,该怎么办?这里将讲解通过使用由 Delphi提供的线程局部存储和 A P I为线程提供同步的方法。   这里先讲线程局部存储,下一篇再讲线程同步 线程局部存储   由于每个线程都代表一个不同的执行路径,因此,最好有一种只限于一个线程内部使用的数据存储方式。要实现上述目的有三种方式: 1) 第一种也是最简单的一种方式是局部变量((基于栈)。   由于每个线程都在各自的栈中,各个线程都将有一套局部变量的副本,这样,就不会互相影响。 2)第二种方式就是把有关信息保存在各自的线程对象中 3)第三种方式就是用Delphi的关键字 threadvar 来声明变量,以利用操作系统级的线程局部存储 1.把信息保存在TThread派生对象中   将相关信息保存在TThread派生对象中,这是一种线程局部存储可选的技术。相对于使用关键字threadvar的技术,这种方式更加简单、更加有效。例如,你可以在一个线程对象中加入下列信息 type TMyThread = class(TThread) private FLocalInt: Integer; FLocalStr: String; .. .

ThreadPoolTaskExecutor 中 corePoolSize vs. maxPoolSize

你说的曾经没有我的故事 提交于 2020-03-30 10:06:55
1. 概览 Spring中的 ThreadPoolTaskExecutor 是一个 JavaBean ,提供围绕 java.util.concurrent.ThreadPoolExecutor 的抽象实例,并作为Spring 中 org.springframework.core.task.TaskExecutor 暴露出来. 此外,它可以通过 corePoolSize、maxPoolSize、queueCapacity、allowCoreThreadTimeOut 和 keepAliveSeconds 的属性进行高度配置。在本教程中,我们将查看 corePoolSize 和 maxPoolSize 属性。 2. corePoolSize vs. maxPoolSize 刚接触到这种抽象的用户可能很容易混淆这两个配置属性的区别。因此,让我们分别看一下。 2.1. corePoolSize corePoolSize 是在不超时情况下,保持活跃的最少线程数 。它是 ThreadPoolTaskExecutor 的一个可配置项。但是, ThreadPoolTaskExecutor* 抽象将该值的设置委托给底层的 java.util.concurrent.ThreadPoolExecutor 。为验证这一点,如果我们将 allowCoreThreadTimeOut 设置为 true

Java并发编程笔记之ArrayBlockingQueue源码分析

守給你的承諾、 提交于 2020-03-30 08:48:26
JDK 中基于数组的阻塞队列 ArrayBlockingQueue 原理剖析,ArrayBlockingQueue 内部如何基于一把独占锁以及对应的两个条件变量实现出入队操作的线程安全? 首先我们先大概的浏览一下ArrayBlockingQueue 的内部构造,如下类图: 如类图所示,可以看到ArrayBlockingQueue 内部有个数组items 用来存放队列元素,putIndex变量标示入队元素的下标,takeIndex是出队的下标,count是用来统计队列元素个数, 从定义可以知道,这些属性并没有使用valatile修饰,这是因为访问这些变量的使用都是在锁块内被用。而加锁了,就足以保证了锁块内变量的内存可见性。 另外还有个独占锁lock 用来保证出队入队操作的原子性,这保证了同时只有一个线程可以进行入队出队操作,另外notEmpty,notFull条件变量用来进行出队入队的同步。 由于ArrayBlockingQueue 是有界队列,所以构造函数必须传入队列大小的参数。 接下来我们进入ArrayBlockingQueue的源码看,如下: public ArrayBlockingQueue(int capacity) { this(capacity, false); } public ArrayBlockingQueue(int capacity, boolean fair

java基础第十六篇之多线程

别说谁变了你拦得住时间么 提交于 2020-03-30 05:44:49
1:线程的概念 进程(任务):一个正在运行的程序 进程的调度:CPU来决定什么时候该运行哪个进程 (时间片轮流法) 线程在一个应用程序中,同时,有多个不同的执行路径,是进程中的实际运作单位。 好处是提高程序效率。 1.2 线程和进程的关系 a:一个进程可以创建多个线程 b:线程必须依赖于进程而存在 c:多个线程共享进程的空间 d:进程和线程得到CPU的机会是均等的‘ 1.3 为什么要搞多线程 我们可以让程序同时执行(并发执行) //Java只让我们创建线程,而不让我们创建进程 HelloWorld.java javac HelloWorld.java java HelloWorld --->JVM 启动进程 Run Application --->JVM 启动进程 //一个进程中至少要有一个线程 main方法 被称为 主线程 2: 线程的创建方式 Thread 类 方式1:继承Thread类 1:自定义一个类,继承Thread类 2:重写Thread类的run方法 3:创建自定义类对象 4:让自定义类对象调用start方法,启动线程 例题: package pack01_thread; public class Demo01Thread { public static void main(String[] args) { //3:创建自定义类对象 MyThread mt = new

【杂谈】从底层看锁的实现2

不打扰是莪最后的温柔 提交于 2020-03-30 05:34:06
前言 我的上一篇博客的案例中,请求锁的线程如果发现锁已经被其他线程占用,它是通过自旋的方式来等待的,也就是不断地尝试直到成功。本篇就讨论一下另一种方式,那就是挂起以等待唤醒。 注:相关代码都来自《Operating System: Three Easy Pieces》这本书。 自旋哪里不好? 先说明一下,自旋也有它的好处,不过这里先不讲,我们先讲它可能存在哪些问题。 我们考虑一个极端的场景,某个电脑只有一个CPU,这时候有2个线程竞争锁,线程A获得了锁,进入临界区,开始执行临界区的代码(由于只有一个CPU,线程A在执行的时候,线程B只能在就绪队列中等待)。结果线程A还没执行完临界区的代码,时间片就用完了,于是发生上下文切换,线程A被换了出去,现在开始执行线程B,线程B就开始尝试获取锁。 这时候尴尬的事情就来了,拥有锁的线程没在运行,也就不能释放锁。而占据CPU的线程由于获取不到锁,就只能自旋直到用完它的时间片。 这还只是2个线程的情况,如果等待的线程有100多个呢,那在轮询调度器的场景下,线程A是不是要等到这100多个线程全部空转完才能运行,这浪费可就大了! 用yield()让出CPU怎么样? yield()方法是把调用线程之间切出,放回就绪队列。这个方法与前面的不同就在于,当线程B恢复执行的时候,它只会尝试一次,如果失败,则直接退出,而不会用完它的整个时间片