`
Tristan_S
  • 浏览: 378707 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

内存模型 - 多线程

 
阅读更多
--------概述---------
需要多任务处理的原因是 计算机的运算速度和它的存储和通讯子系统速度的差距太大,大部分时间都花在了磁盘IO,网络通信和数据访问上。
使用一些手段把处理器的运算能力压榨出来, 否则就会造成很大的浪费。

高速缓存  内存和CPU之间有几个数量级的差距,所以引入了高速缓存,用以通讯。
这就导致了缓存一致性的问题。

主内存,工作内存和Java内存区域中的堆栈方法区并不是同一个层次。如果要勉强对应起来
内存 -->  主内存   --> Java堆中的对象实例
寄存器/高速缓存  -->  工作内存 --> 对应了jvm栈中部分区域,



------栈堆方法区---------
栈:可以分为JVM栈(执行字节码) 本地方法栈(执行Native方法)
JVM栈: 线程私有的, 生命周期与线程相同,存储局部/本地变量表(基本数据类型,对象引用)

堆: 所有对象实例 和 数组  常量池, 成员变量(包括基本数据类型int)
常量池 http://www.cnblogs.com/devinzhang/archive/2012/01/25/2329463.html


方法区:也称永久代,不会被回收, 存储类信息,常量,静态变量
运行时常量池: 是方法区的一部分,String 的intern方法可以将数据放入
String str1="wang";
String str2=(new String("wang")).intern();
System.out.println(str1==str2); //true

使用方式
Object obj = new Object();
Object obj 反映到栈的本地变量表中, 作为一个reference类型数据出现
new Object()  反映到堆中,形成一块内存空间
对中还包含了能查找到此对象类型数据(对象类型,父类,接口,方法等),存放在方法区中

----------线程池------------
         如果访问服务器的客户端很多,那么服务器要不断的创建和销毁线程, 这样将严重影响服务器的性能,如果真的来一名学员,我们就安排一名新的 工作人员为之服务,这也是不可能的,那么公司岂不是要招很多工作人员.
应该是一名工作人员服务完一名学员,空闲下来后,一旦有新的学员要服务,
我们安排该工作人员,为之服务.
        线程池的概念于此类似,首先创建一些线程,他们的集合称为线程池,
当服务器接收到一个客户请求后,就从线程池中取出一个空闲的线程为之服
务,服务完成后不关闭该线程,而是将该线程还回到线程池中.
        在线程池的编程模式下,任务是交给整个线程池,而不是直接交给某个线
程,线程池拿到任务偶,他就在内部找有空闲的线程,再把任务交给内部某个
空闲的线程,这就是封装.记住,任务是交给整个线程池,但可以同时向一个线程池中提交多个任务.
Log-monitor 中不是开所有的线程去访问32个instance上的日志, 而是只开10个,然后等这些结束后,继续执行剩下的


---------AtomicInteger--------
i++ 不是线程安全的,如果多个线程从1加到100 结果会小于100 需要用到synchronized
在i已从内存中取到最新值, 但未与1进行运算, 此时其他线程已数次将运算结果赋值给i.
则当前线程结束时, 之前的数次运算结果都将被覆盖. (非原子性)

AtomicInteger 是线程安全的,
调用了volatile,volatile保证每次取a的值都不是从缓存中取的,而是从a真正对应的内存地址,但它不能保证原子性。(可见性 )

区别于synchronized这种悲观锁,导致其他所有需要锁线程挂起,等待持有锁的线程释放锁。
CAS (Compare And Swap)  是一种乐观锁的机制
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
private volatile int value;

public final int get() {
        return value;
    }

 public final int incrementAndGet() {
        for (;;) {
            int current = get();
            int next = current + 1;
            if (compareAndSet(current, next))
                return next;
        }
    }

在这里采用了CAS操作,每次从内存中读取数据然后将此数据和+1后的结果进行CAS操作,如果成功就返回结果,否则重试直到成功为止。
而compareAndSet利用JNI来完成CPU指令的操作。
public final boolean compareAndSet(int expect, int update) {   
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }


整体的过程就是这样子的,利用CPU的CAS指令,同时借助JNI来完成Java的非阻塞算法。其它原子操作都是利用类似的特性完成的。


-----------内存模型------------
http://www.myexception.cn/other/1017209.html

在java中,所有实例域、静态域和数组元素存储在堆内存中,堆内存在线程之间共享(本文使用“共享变量”这个术语代指实例域,静态域和数组元素)。局部变量(Local variables),方法定义参数(java语言规范称之为formal method parameters)和异常处理器参数(exception handler parameters)不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。

线程A与线程B之间如要通信的话,必须要经历下面2个步骤:

首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
然后,线程B到主内存中去读取线程A之前已更新过的共享变量。

如上图所示,本地内存A和B有主内存中共享变量x的副本。假设初始时,这三个内存中的x值都为0。线程A在执行时,把更新后的x值(假设值为1)临时存放在自己的本地内存A中。当线程A和线程B需要通信时,线程A首先会把自己本地内存中修改后的x值刷新到主内存中,此时主内存中的x值变为了1。随后,线程B到主内存中去读取线程A更新后的x值,此时线程B的本地内存的x值也变为了1。


java内存模型JMM主要是为了规定线程和内存之间的一些关系.
系统存在一个主内存, java中所有实例变量都存储在主内存中,对于所有线程是共享的
.每条线程都有自己的工作内存, 工作内存由缓存和堆栈两部分组成, 缓存中保存的是主存中变量的拷贝,
缓存不总和主存同步,也就是缓存中变量的修改可能没有立刻写到
主存中,堆栈中保存的是线程的局部变量,线程之间无法相互直接访问堆栈中的变量.

线程的working memory工作内存是cpu的寄存器和高速缓存的抽象描述:现在的计算机,cpu在计算的时候,并不总是从内存读取数据,它的数据读取顺序优先级 是:寄存器-高速缓存-内存。线程耗费的是CPU,线程计算的时候,原始的数据来自内存,在计算过程中,有些数据可能被频繁读取,这些数据被存储在寄存器和高速缓存中,当线程计算完后,这些缓存的数据在适当的时候应该写回内存。当多个线程同时读写某个内存数据时,就会产生多线程并发问题,

原子性,有序性,可见性

原子性,对除了long和double之外的基本类型的简单操作都具有原子性。简单操作就是赋值或者return。比如”a = 1;”和 “return a;”这样的操作都具有原子性。但是在Java中,类似”a += b”这样的操作不具有原子性。
对long和double的简单操作不具有原子性。但是,一旦给这两个类型的属性加上volatile修饰符,对它们的简单操作就会具有原子性。


synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。
volatile可以保证内存可见性,不能保证并发有序性。

AtomicInteger 中用volatile解决可见性问题, 用CAS来解决有序性问题


--------ThreadLocal---------
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。  不存在变量共享的问题


-------线程安全的实现方法--------
1> 互斥同步 synchronized   Lock(不推荐)
2> 非阻塞同步 CAS Compare And Swap   
AtomicInteger
3> 无同步方案  不涉及共享数据, 一般的web应用
临时变量, ThreadLocal

总结 用同步的方式来解决多线程问题,是由于用到了共享变量,如果没有共享变量则无需用同步。

---------共享数据类型------------
1> 不可变 final修饰的基本数据类型

2> 绝对线程安全  定义: 调用者不需要任何额外的同步措施
没有绝对安全的,多线程频繁的对Vector进行add get remove 操作,也会出现数组越界异常。
需要用到同步块synchronized(vector){....}

3> 相对线程安全
Vector HashTable

4> 线程兼容 (线程不安全)
ArrayList  HashMap

package com.hp.hpsc.logservice.client;

import java.util.Vector;

public class TestVector {
	private static Vector<Integer> vector = new Vector<Integer>();
	
	public static void main(String[] args) {
		while(true){
			for (int i = 0; i < 10; i++) {
				vector.add(i);
			}
			
			Thread removeThread = new Thread(new Runnable(){
				@Override
				public void run() {
					for (int i = 0; i < vector.size(); i++) {
						vector.remove(i);
					}
				}
				
			});
			
			Thread printThread = new Thread(new Runnable(){
				@Override
				public void run() {
					for (int i = 0; i < vector.size(); i++) {
						System.out.println(Thread.currentThread().getName() +":" + vector.get(i));
					}
				}
				
			});
			
			removeThread.start();
			printThread.start();
			
			while (Thread.activeCount() > 20); 
		}
	}
}



异常
Exception in thread "Thread-1293" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 12
	at java.util.Vector.get(Vector.java:694)
	at com.hp.hpsc.logservice.client.TestVector$2.run(TestVector.java:28)
	at java.lang.Thread.run(Thread.java:619)
分享到:
评论

相关推荐

    内存模型-多线程内存模型

    ### C++09内存模型与多线程编程 #### 一、引言 随着多核处理器的普及,多线程编程成为了现代软件开发中的一个重要组成部分。C++作为一门广泛使用的编程语言,在C++09标准中引入了一系列重要的新特性,其中最显著的...

    TCP并发服务器模型-多线程TCP服务器

    本文将深入探讨如何在rt-thread操作系统环境下实现一个高效的多线程TCP并发服务器模型。 rt-thread是一个开源、实时、轻量级的操作系统,特别适合于嵌入式设备。它提供了丰富的API接口,支持网络协议栈,使得开发者...

    深入Java内存模型-JMM

    Java内存模型,简称JMM(Java Memory Model),是Java虚拟机规范中定义的一个抽象概念,它描述了在多线程环境下,如何保证各个线程对共享数据的一致性视图。JMM的主要目标是定义程序中各个变量的访问规则,以及在...

    java内存模型和一些多线程的资料

    Java内存模型(JVM Memory Model,简称JMM)是Java平台中的一个重要概念,它定义了在多线程环境下,如何在共享内存中读写变量的行为。JMM的主要目标是确保多线程环境下的可见性、有序性和原子性,从而避免数据不一致...

    php-多线程扩展

    在实际应用中,"php-多线程扩展"可以与PHP的其他组件如PDO(数据库访问)、cURL(HTTP客户端)或者Redis(内存数据存储)结合使用,以多线程方式并行处理数据库查询、网络请求或者缓存操作,大大提高系统的并发处理...

    多线程精品资源--多线程与高并发.zip

    此外,线程间通信(如wait/notify、生产者消费者模型)也是多线程编程中的重要概念。 高并发是指系统在同一时间能处理大量并发请求的能力。在互联网服务中,高并发处理能力直接影响到系统的可扩展性和性能。为了...

    JVM内存模型-重排序&内存屏障 1

    Java内存模型(JVM Memory Model)是Java编程语言中用于定义如何在多线程环境下共享变量的规则。在这个模型中,内存屏障(Memory Barrier)和重排序(Reordering)是两个关键概念,它们对并发编程的正确性和性能有着...

    java课件-5-多线程

    此外,Java内存模型(JMM)也是多线程编程中的重要概念,它定义了线程如何共享和访问内存,以及如何确保内存可见性。volatile关键字可以确保变量对所有线程可见,而final关键字则保证初始化的值不会被其他线程改变。...

    cpp-多线程版的Twemproxy

    4. **非阻塞I/O**:结合异步I/O或事件驱动模型(如Epoll、Kqueue),可以进一步提高多线程Twemproxy的效率,使其在等待网络I/O时能处理其他请求,而不是简单地阻塞。 5. **性能监控**:为了确保多线程版本的稳定性...

    Java内存模型--原子性;有序性;可见性1

    在Java编程语言中,内存模型(Java Memory Model, JMM)是理解和解决多线程并发问题的关键。本文将深入探讨JMM中的三个核心概念:原子性、有序性和可见性。 ### 1. 原子性(Atomicity) 原子性是指一个操作或多个...

    java内存模型详解--非常经典

    Java内存模型(JVM Memory Model,简称JMM)是Java平台中的一个重要概念,它定义了程序中各个变量的访问规则,以及在多线程环境下的内存一致性效果。JMM主要解决的是并发环境下不同线程之间如何共享数据以及如何保证...

    linux编程技术-多线程-网络编程

    本资料集专注于"Linux编程技术-多线程-网络编程",它涵盖了UNIX环境高级编程、Linux网络编程、Linux多线程编程、Linux窗口编程以及Linux脚本编程等多个核心主题。这些内容都是构建高效、可靠且可扩展的Linux应用的...

    Java并发编程(17)深入Java内存模型-内存操作规则

    本篇文章将深入探讨Java内存模型(JMM, Java Memory Model),以及其中的内存操作规则。 Java内存模型定义了在并发环境中,如何在不同线程之间共享数据以及保证数据一致性的一组规范。它主要关注的是处理器内存和...

    并发编程基础知识,java内存模型及多线程、volatile

    ### 并发编程基础知识,Java内存模型及多线程、volatile #### Java内存模型(JMM) Java内存模型(Java Memory Model, JMM)是Java并发编程的基础之一,它定义了一套规则来保证线程之间的数据可见性和一致性。当程序...

    OC-多线程-上下文切换

    当我们谈论“OC-多线程-上下文切换”时,我们实际上是在讨论Objective-C中多线程环境下的一个核心概念。上下文切换是操作系统调度线程执行的一种机制,它涉及到保存当前线程的状态并恢复另一个线程的状态,以便线程...

    73道Java面试题合集-多线程与进程

    9. **Java内存模型(JMM)**: - 描述了线程如何访问和修改共享变量,确保并发场景下的正确性。 - 主要概念包括主内存、工作内存、happens-before原则等。 10. **线程安全**: - 线程安全是指在多线程环境下,对...

    人工智能-项目实践-多线程-一个多线程多进程的下载DEMO.zip

    在本项目实践中,我们主要探讨的是如何利用多线程和多进程技术来提高下载效率,特别是在人工智能相关的场景中。多线程和多进程是计算机科学中的核心概念,它们允许程序同时执行多个任务,从而实现并发处理,提升系统...

    MFC教程lesson 15-多线程&聊天室.rar

    在本MFC教程Lesson 15中,我们将深入探讨多线程编程以及如何利用MFC(Microsoft Foundation Classes)框架创建一个简单的聊天室应用。多线程是现代软件开发中的一个重要概念,它允许程序同时执行多个任务,提高了...

Global site tag (gtag.js) - Google Analytics