Java并发编程基础

1. 并发

1.1. 什么是并发?

并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力。如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互性将大大改善。现代的PC都有多个CPU或一个CPU中有多个核。是否能合理运用多核的能力将成为一个大规模应用程序的关键。

1.2. 进程 vs. 线程

进程是以独立于其他进程的方式运行的,进程间是互相隔离的。一个进程无法直接访问另一个进程的数据。进程的资源诸如内存和CPU时间片都是由操作系统来分配。

线程又被称为轻量级进程。每个线程有它独自的调用栈, 但是在同一进程下的线程又能互相访问它们间的共享数据。每个线程都有它独自的缓存。如果一个线程读取了某些共享数据,那么它将这些数据存放在自己的缓存中以供将来再次读取。

一个JAVA应用程序默认以一个进程的形式运行着。在一个JAVA程序中,你将协同多个不同的线程一起完成并行运算或实现异步行为。

2. 并发的改进与问题

2.1. 并发性能的上限

之所以并发号称能较快的完成某些任务是因为这些任务能被分组成多个子任务,并且这些子任务能被并行的执行。所以一个任务的实际运行效率将受限于该任务中能并行执行的部分。

一个程序理论上可达到的最高并发性能可通过以下一个被称为Amdahl 定律来计算出:

设F为一个程序中不能被并行执行的百分比,N是处理器的数量,那么理论上该程序能获得的最高并发性能将可能是1/ (F+ ((1-F)/n)).

2.2. 并发问题

线程有独自的调用栈,但是又能互相访问共享的数据。所以这里你会遇到两个问题,可见性和访问。

可见性问题发生于如果线程A先读取了某些共享数据,之后线程B对这些数据进行了修改,那么线程A可能看不到线程B对这数据的改动。

访问问题发生于于 多个线程同时访问修改同一个共享数据。

可见性及访问问题将导致

  • 活跃性失败:由于并发访问数据导致程序无任何反应。 譬如,死锁。
  • 安全性失败:程序创建了错误的数据。

3. JAVA中的并发

3.1. 进程与线程

一个JAVA程序默认以一个线程运行在自己的进程中。JAVA语言通过Thread相关代码来支持线程。JAVA程序可通过Thread这个类来创建线程。从JAVA1.5起,在java.util.concurrent中提供了改进的并发库。

3.2. 锁和线程同步

JAVA提供了“锁” 机制来保护代码片段免于被多个线程在同一时刻运行。最简单的锁住一个方法或一个类就是在该方法或类前添加synchronized关键字

在Java中synchronized关键字保证了:

  • 在同一时刻,只有单个线程能访问这块代码
  • 每个进入这同步代码块的线程都将能看到之前持有相同锁进入的线程的所做的改动

对于线程间的可靠通讯及互斥访问 来说,同步是非常必要的

你可以在定义方法时使用synchronized关键字。这个关键字保证了同一时刻只有一个线程能运行这个方法。其他同样调用了这个方法的线程将被阻塞直到第一个线程离开这个方法。

public synchronized void critial() {
// some thread critical stuff
// here
}

你同样也能用synchronized关键字来保护方法中的代码块。这块代码将由一个关键对象来保护,该关键对象可以是个string或其他object。这个关键对象就被称为 lock。所有被相同lock保护的代码在同一时刻只能被单个线程执行。

举例来说,以下的数据结构将保证同时只有单个线程可以访问add和next方法

package de.vogella.pagerank.crawler;

import java.util.ArrayList;
import java.util.List;
/*** Data structure for a web crawler. Keeps track of the visited sites and keeps
* a list of sites which needs still to be crawled.
* @author Lars Vogel
*/
<pre>public class CrawledSites {
private List<String> crawledSites = new ArrayList<String>();
private List<String> linkedSites = new ArrayList<String>(); public void add(String site) {
synchronized (this) {
if (!crawledSites.contains(site)) {
linkedSites.add(site);
}
}
}
/** * Get next site to crawl. Can return null (if nothing to crawl) */
public String next() {
if (linkedSites.size() == 0) {
return null;
}
synchronized (this) {
<em>// Need to check again if size has changed</em>
if (linkedSites.size() > 0) {
String s = linkedSites.get(0);
linkedSites.remove(0);
crawledSites.add(s);
return s;
}
return null;
}
} }

3.3. Volatile

如果一个变量声明时使用了volatile 关键字,那么该关键字保证了,任何读取该变量的线程都将读到最新写进该变量的值。但volatile 关键字不会保证变量上的任何互斥访问

As of Java 5 write access to a volatile variable will also update non-volatile variables which were modified by the same thread. This can also be used to update values within a reference variable, e.g. for a volatile variable person. In this case you must use a temporary variable person and use the setter to initialize the variable and then assign the temporary variable to the final variable. This will then make the address changes of this variable and the values visible to other threads.

因为在JAVA 5中,对一个声明了volatile 的变量进行写操作会导致该写操作所在该线程之前所有的对非volatile 变量的修改进行同步更新。这也可用来更新引用类型变量。例如,有个volatile 类型的变量person。你必须创建一个临时变量person,然后调用SETTER方法来初始化这变量然后将临时变量赋值给final变量。 这会使这个变量的地址发生改变并且此变量的值对于其他线程变为可见。

4. JAVA 内存模型

4.1. 概览

JAVA内存模型描述了线程内存与主存间的通讯关系。

JAVA内存模型定义了线程内的内存改变将怎样传递到其他线程的规则,同样也定义了线程内存与主存进行同步的场景,也描述了哪些操作属于原子操作及操作间的顺序。

4.2. 原子操作

一个原子操作是指一个执行时不会被其他操作影响到的最小单位的操作。

JAVA语言规范保证了对一个变量的读和写操作都是原子的(除了LONG和DOUBLE类型的变量)。对于LONG或DOUBLE类型的变量,只有当这些变量声明时使用了volatile关键字才是原子的

假设定义了一个INT变量I,那么在java中,I++操作不是一个原子操作。同样,这对于其他数字类型的变量也都不是一个原子操作。

I++操作先从I中读取了当前值(这是个原子操作)然后再让它加上1写回(原子操作)。但是在读和写这两个操作间,I的值有可能被改变。

从JAVA1.5起,JAVA提供了原子变量,例如AtomicInteger 或 AtomicLong 都提供了类似 getAndDecrement()getAndIncrement() 及 getAndSet()等原子方法。

4.3.同步代码块的内存更新

JAVA内存模型保证了每个进入相同锁同步块的线程都能看到之前进入的其他所有线程修改的结果。

Java并发编程基础的更多相关文章

  1. 并发-Java并发编程基础

    Java并发编程基础 并发 在计算机科学中,并发是指将一个程序,算法划分为若干个逻辑组成部分,这些部分可以以任何顺序进行执行,但与最终顺序执行的结果一致.并发可以在多核操作系统上显著的提高程序运行速度 ...

  2. Java并发编程--基础进阶高级(完结)

    Java并发编程--基础进阶高级完整笔记. 这都不知道是第几次刷狂神的JUC并发编程了,从第一次的迷茫到现在比较清晰,算是个大进步了,之前JUC笔记不见了,重新做一套笔记. 参考链接:https:// ...

  3. Java并发编程基础-线程安全问题及JMM(volatile)

    什么情况下应该使用多线程 : 线程出现的目的是什么?解决进程中多任务的实时性问题?其实简单来说,也就是解决“阻塞”的问题,阻塞的意思就是程序运行到某个函数或过程后等待某些事件发生而暂时停止 CPU 占 ...

  4. java并发编程基础概念

    本次内容主要讲进程和线程.CPU核心数和线程数.CPU时间片轮转机制.上下文切换,并行和并发的基本概念以及并发编程的好处和注意事项,为java并发编程打下扎实基础. 1.什么是进程和线程 1.1 进程 ...

  5. 多线程(一)java并发编程基础知识

    线程的应用 如何应用多线程 在 Java 中,有多种方式来实现多线程.继承 Thread 类.实现 Runnable 接口.使用 ExecutorService.Callable.Future 实现带 ...

  6. Java并发编程基础三板斧之Semaphore

    引言 最近可以进行个税申报了,还没有申报的同学可以赶紧去试试哦.不过我反正是从上午到下午一直都没有成功的进行申报,一进行申报 就返回"当前访问人数过多,请稍后再试".为什么有些人就 ...

  7. Java并发编程基础之volatile

    首先简单介绍一下volatile的应用,volatile作为Java多线程中轻量级的同步措施,保证了多线程环境中“共享变量”的可见性.这里的可见性简单而言可以理解为当一个线程修改了一个共享变量的时候, ...

  8. java并发编程基础——线程的创建

    一.基础概念 1.进程和线程 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据 ...

  9. Java并发编程基础-ReentrantLock的机制

    同步锁: 我们知道,锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源,在Lock接口出现之前,Java应用程序只能依靠synchronized关键字来实现同步锁 ...

随机推荐

  1. SSH2框架实现注冊发短信验证码实例

    这两天開始写程序了,让用SSH2框架,曾经没有接触过Java项目更没有接触过SSH2框架,所以用注冊開始了我Java之旅.后来发现,后台代码挺easy理解的,跟.net的差点儿相同.就是层与层之间的调 ...

  2. github初使用

    http://www.eoeandroid.com/thread-274556-1-1.html 其中编写 $ git remote add origin <a href="\&quo ...

  3. LeetCode242——Valid Anagram

    Given two strings s and t, write a function to determine if t is an anagram of s. For example, s = & ...

  4. date 增加一个小时 减少一个小时

    # date -s `date -d -1hour +%T`

  5. MYSQL IO innodb-buffer-pool

    http://mysql.taobao.org/monthly/2016/02/02/ MySQL · 性能优化· 5.7.6 InnoDB page flush 优化 MySQL · 性能优化· I ...

  6. mini filter driver sql server

    https://blogs.msdn.microsoft.com/sql_pfe_blog/2013/04/23/identifying-the-cause-of-sql-server-io-bott ...

  7. linux 双显卡问题。。。

    bumblebee的作用是禁用nvidia独立显卡,需要使用独显时,使用”optirun 程序名“手动开启nvidia来运行需要加速的程序,如optirun vmware. 打开N卡设置: optir ...

  8. cocos2d-x中几种存储数据的方式

    说明:本文所论述内容均基于cocos2dx 3.0 版本. 1.UserDefault 它是cocos2d-x用来存取基本数据类型用的.保存为XML文件格式. 查看CCUserDefault文件,可以 ...

  9. C#集合概述

    C#集合概述 2016-11-29 集合 顺序排列 连顺存储 直接访问方式 访问时间 操作时间 备注 Dictionary 是 Key Key:O(1) O(1) 访问性能最快,不支持排序 Sorte ...

  10. python 合并字典,相同 key 的 value 如何相加?

    x = { 'apple': 1, 'banana': 2 } y = { 'banana': 10, 'pear': 11 } 需要把两个字典合并,最后输出结果是: { 'apple': 1, 'b ...