java并发编程实战阅读总结(a)

1、锁(lock)与volatile
(1)、隐式锁,java提供了强制原子性的内置锁机制:synchronized块或synchronized方法。
操作共享状态的复合操作必须是原子的,以避免竞态条件,比如读-改-写操作和检查再运行操作。
复合操作会在完整的运行期占有锁,以确保其行为为原子的。
不管是同步代码块还是同步方法,每次只有一个线程可以进入,如果其他线程试图进入(不管是同一同步块还是不同的同步块),
JVM会将它们挂起(放入到等锁池中)。这种结构在并发理论中称为临界区。
这里我们可以对Java中用synchronized实现同步和锁的功能做一个总结

静态同步方法会锁定它的Class对象
同步方法可以视为包含整个方法的synchronized(this) { … }代码块
synchronized修饰符并不是方法签名的组成部分,所以不能出现在接口的方法声明中
非同步的方法不关心锁的状态,它们在同步方法运行时仍然可以得以运行
synchronized实现的锁是可重入的锁。

在JVM内部,为了提高效率,同时运行的每个线程都会有它正在处理的数据的缓存副本,当我们使用synchronzied进行同步的时候,真正被同步的是在不同线程中表示被锁定对象的内存块简单的说就是在同步块或同步方法执行完后,对被锁定的对象做的任何修改要在释放锁之前写回到主内存中;在进入同步块得到锁之后,被锁定对象的数据是从主内存中读出来的,持有锁的线程的数据副本一定和主内存中的数据视图是同步的

(2)、volatile关键字:volatile修饰变量或对象,被volatile修饰的变量或对象告诉vm从内存中读取该变量、对象的值

变量的值在使用之前总会从主内存中再读取出来。

对变量值的修改总会在完成之后写回到主内存中。


volatile不能保证多线程中的同步,但是可以保证在多线程中数据是可见的。


(3)、显式锁 Lock 和 ReentrantLock
与内置锁机制不同的是,Lock提供了一种无条件的、可轮询的、定时的以及可中断的锁获取操作,所有加锁和解锁方法都是显示的。
lock能实现synchronized实现的所有功能,lock()的使用更加方便灵活、功能更加强大。

lock分别为读、写提供了锁,这样效率更高。
public interface Lock {
    //获取锁
    void lock();
    //如果当前线程未被中断,则获取锁。
    void lockInterruptibly() throws InterruptedException;
    //仅在调用时锁为空闲状态才获取锁
    tryLock();
    //如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
    tryLock(long time,TimeUnit unit);
    //返回绑定此Lock实例的新Condition实例。
    Condition newCondition();
}lock方法获取不到锁则阻塞,tryLock获取不到锁不阻塞直接返回false。


lock带来灵活、方便的同时也引入隐患就是死锁,lock的释放unlock需要在finally代码块里释放锁,如果没有释放锁很可能程序运行不下去,造成死锁。

Lock lock = new ReentrantLock();
lock.lock();
try {// update object state
}
finally {lock.unlock();
}
必须在finally 中来释放Lock

这也是使用synchronized比使用lock简单的一个点。

synchronized和ReentrantLock之间的选择:
ReentrantLock在加锁和内存上提供的语义与内置锁相同,此外它还提供了一些其他功能,包括定时等待,可中断的锁等待,公平性,以及实现非块结构的加锁。
同时ReentrantLock为读、写分别提供了锁机制,强制的进行了分离。
然而ReentrantLock的危险性比同步机制要高,如果忘记在finally块中调用unlock,那么虽然代码表面上正常运行,
但实际上已经埋下了一颗定时炸弹,并可能伤及其他代码。仅内置锁不能满足需求时,才可以考虑使用ReentrantLock.
在一些内置锁无法满足需求时,ReentrantLock可以作为一种高级工具,当需要一些高级功能时才应该使用ReentrantLock,
这些功能包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。
否则,还应该优先使用synchronized。ReentrantLock的非块结构仍然意味着,获取锁的操作不能与特定的栈帧关联起来,而内置锁则可以。

(4)、锁的唤醒:

notify 和 notifyAll:
在条件队列API中有两个发出通知的方法,即 notify和 notifyAll。无论调用哪一个,都必须持有与条件队列对象相关联的锁。notify操作会选在条件队列中的一个线程唤醒,其他线程则无法得到唤醒通知。而notifyAll则会唤醒所有等待在条件队列中的线程来竞争锁。使用notify单一的同时可能发生信号丢失问题。
普遍认可的做法是优先使用notifyAll而不是notify。虽然notifyAll可能比notify更低效,但却更容易确保类的行为是正确的。

注意:notify()对于只有一个线程时是有意义的,多线程时需要使用notifyAll(),由于notify()和notifyAll()不精确,因此建议使用信号量或阻塞队列来实现对共享资源的加锁。

2、并发集合ConcurrentHashMap

先说下HashMap:其是线程不安全的,没有同步的机制,在多线程执行时可能会造成数据的错乱,并且效率也低。HashMap底层实现机制是一个数组,数组中的每个元素又是一个单链表,只有hashcode值冲突的元素才放到这个单链表中。HashMap中的元素是由key与value封装成的Entity对象,这是造成其占用很大内存空间的根本原因,其次是他的默认大小是16,在需要增长时增长到原来的2倍,并且还是2的N次方。

ConcurrentHashMap即使线程安全的又是高效的。通过源码分析他的底层实现机制是一个segment数组,即段数组。将数组中的元素分为若干段,每一段对应一个锁,这可以达到锁分离的目的,对其中一段的访问不影响其他的元素,提交了效率。他的并发度是16,是构造器中的一个参数。


3、通过共享对象达到共享数据的目的
(1)、设计线程安全的类。
     找出构造对象状态的所有变量。
     约束状态变量的不变性条件。
     建立对象状态的并发访问管理策略。
(2)、实例封闭
     如果某对象不是线程安全的,我们可以通过多种技术使其在多线程中能安全的使用。确保该对象只能由单个线程访问。
public class AnimalSet{  
         private final Set<Animal> mySet = new HashSet<Animal>();  
           
         public sychronized void addAnimaln(Animal p) {  
              mySet.add(p)  
         }  
      
         public sychronized boolean containsAnimal(Animal p) {  
              return mySet.contains(p);  
         }  
    }  


虽然HashSet并非线程安全的。但是mySet是私有的不会逸出。唯一能访问mySet的代码是addPerson()和containsPerson()。
在执行上他们都要获的PersonSet 上的锁。PersonSet的状态完全又它的内置锁保护。所以AnimalSet是一个线程安全的类。


4、基础模块


(1)、同步容器类。线程安全的容器包括Vector和Hashtable。同步的封装容器类由Collections.sychronizedXXX工厂方法创建。
     eg:synchronizedList,synchronizedMap(m)、synchronizedSet(s)这些是通过synchronized同步方法来实现的,达到了线程安全但是效率低
(2)、同步工具类。
     阻塞队列(BlockingQueue(LinkedBlockingQueue,ArrayBlockingQueue,PriorityBlockingQueue,SynchronousQueue))不仅可以保存对象的容器,而且还可以协调生产者和消费者之间的控制流。
     信号量(Semaphore):用来控制同时访问某个特定资源的操作数量。通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。Semaphore允许线程获取许可, 未获得许可的线程需要等待.这样防止了在同一时间有太多的线程执行。Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。
 eg:模拟30辆车去泊车,而车位有10个的场景. 当车位满时,出来一辆车,才能有一辆车进入停车.

转载 http://mouselearnjava.iteye.com/blog/1921468

package my.concurrent.semaphore;  import java.util.concurrent.Semaphore;  public class Car implements Runnable {  private final Semaphore parkingSlot;  private int carNo;  /** * @param parkingSlot * @param carName */  public Car(Semaphore parkingSlot, int carNo) {  this.parkingSlot = parkingSlot;  this.carNo = carNo;  }  public void run() {  try {  parkingSlot.acquire();  parking();  sleep(300);  parkingSlot.release();  leaving();  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  private void parking() {  System.out.println(String.format("%d号车泊车", carNo));  }  private void leaving() {  System.out.println(String.format("%d号车离开车位", carNo));  }  private static void sleep(long millis) {  try {  Thread.sleep(millis);  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  }  package my.concurrent.semaphore;  import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Semaphore;  public class ParkingCars {  private static final int NUMBER_OF_CARS = 30;  private static final int NUMBER_OF_PARKING_SLOT = 10;  public static void main(String[] args) {  /* * 采用FIFO, 设置true */  Semaphore parkingSlot = new Semaphore(NUMBER_OF_PARKING_SLOT, true);  ExecutorService service = Executors.newCachedThreadPool();  for (int carNo = 1; carNo <= NUMBER_OF_CARS; carNo++) {  service.execute(new Car(parkingSlot, carNo));  }  sleep(3000);  service.shutdown();  /* * 输出还有几个可以用的资源数 */  System.out.println(parkingSlot.availablePermits() + " 个停车位可以用!");  }  private static void sleep(long millis) {  try {  Thread.sleep(millis);  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  }  

运行结果:
1号车泊车 
4号车泊车 
9号车泊车 
2号车泊车 
8号车泊车 
10号车泊车 
3号车泊车 
12号车泊车 
14号车泊车 
6号车泊车 
2号车离开车位 
4号车离开车位 
6号车离开车位 
1号车离开车位 
9号车离开车位 
3号车离开车位 
5号车泊车 
8号车离开车位 
10号车离开车位 
11号车泊车 
7号车泊车 
12号车离开车位 
13号车泊车 
14号车离开车位 
16号车泊车 
17号车泊车 
20号车泊车 
19号车泊车 
18号车泊车 
15号车泊车 
5号车离开车位 
20号车离开车位 
18号车离开车位 
22号车泊车 
11号车离开车位 
7号车离开车位 
13号车离开车位 
15号车离开车位 
21号车泊车 
26号车泊车 
23号车泊车 
28号车泊车 
25号车泊车 
16号车离开车位 
27号车泊车 
17号车离开车位 
30号车泊车 
24号车泊车 
29号车泊车 
19号车离开车位 
25号车离开车位 
24号车离开车位 
22号车离开车位 
26号车离开车位 
28号车离开车位 
30号车离开车位 
21号车离开车位 
23号车离开车位 
27号车离开车位 
29号车离开车位 
10 个停车位可以用!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/464608.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我也确实很向往深圳这种拼搏的精神

今天跟个同学聊天&#xff0c;是关于他的offer选择&#xff0c;他拿了一个不错的外企岗位offer&#xff0c;这个offer的薪资是他现在薪资两倍还多一些&#xff0c;他现在人在外地&#xff0c;年后准备来深圳工作&#xff0c;他在微信说让我给些建议。首先我肯定的是&#xff0c…

VBA语法基础

数据类型 “数据类型”是指如何将数据存储在内存中。 (1)Boolean 表示逻辑数据&#xff0c;可以是True或False中的任一个值。占用2字节的存储空间&#xff0c;取值范围为True或False&#xff0c;缺省值为False。 (2)Byte 只能表示正数。占用1字节的存储空间&#xff0c;取值范围…

clamav Java_ClamAV安装使用及API例子

ClamAV是一款由Sourcefire组织开发的开源杀毒引擎&#xff0c;Sourcefire同时也是Snort入侵检测引擎的所有者。ClamAV提供了一种更为快速灵活的框架用以检测恶意代码和软件产品。可以作为现有的台式机、文件服务器、邮件服务器以及其他需要杀毒扫描软件场景中杀毒扫描软件的补充…

PHP json_encode后的数据有的大括号于中括号

当array是一个从0开始的连续数组时&#xff0c;json_encode出来的结果是一个由[]括起来的字符串。 而当array是不从0开始或者不连续的数组时&#xff0c;json_encode出来的结果是一个由{}括起来的key-value模式的字符串。转载于:https://www.cnblogs.com/xxllzizi/p/9836469.ht…

第一次使用 Blog

不喜欢BBS上不负责任的灌水&#xff0c;希望有一个记载自己日常心态和工作中所用到的有用技术的平台&#xff0c;作为自己以后的一个回顾&#xff0c;也与大家一同分享。很久就想拥有自己的Blog了&#xff0c;但这第一次使用 Blog &#xff0c;还是有点兴奋&#xff0c;Blog这个…

中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux

去年 6 月份&#xff0c;中科院大学教授、中科院计算所研究员包云岗&#xff0c;发布了开源高性能 RISC-V 处理器核心 —— 香山。近日&#xff0c;包云岗在社交平台晒出图片&#xff0c;香山芯片已流片&#xff0c;回片后进行了串口调通&#xff0c;1 月 24 日成功运行了 Linu…

java并发编程实战阅读总结(b)

5、Executor框架 Executor框架是并发集合java.util.concurrent中的一个成员。 Executor为灵活且强大的异步任务执行框架提供了基础&#xff0c;还提供了对生命周期的支持&#xff0c;以及统计信息、应用管理机制和性能监视等机制。Executor 最早是为了解决生产者-消费者模式而…

公司那些事-关于领导

首先,请允许我将范围限定一下,本文中的领导,并不是指那些了不起的大人物,而是说IT企业中的,我们身边的组长,经理,部长等等,之所以这么限定,原因非常简单,本人只接触过这个层面的领导. 领导也是普通人在我们中间,经常有意无意的对领导提出一些比较高的要求,比如领导应该是技术专…

java io流操作_十个Demo进行讲解Java中IO流的常用操作~

好久不见的IO流对IO流的学习&#xff0c;我记得还是初学Java基础的时候&#xff0c;后来找工作过程中经常看到有些招聘信息中写到熟悉IO流&#xff0c;现在想想IO流&#xff0c;真的是一脸懵逼&#xff0c;不说这么多废话了&#xff0c;IO流这次好好整理一下。说说IO流的类别在…

这些应用仍未兼容安卓新版本,系统升级后将无法使用

8月7日&#xff0c;谷歌正式发布Android 9 Pie&#xff0c;至今已两月有余。近日&#xff0c;华为终端开放实验室对国内主流应用在Android 9 Pie的兼容性进行测试&#xff0c;结果显示&#xff1a;目前TOP3000应用兼容率已经超过95%&#xff0c;但仍有少量应用存在启动失败、闪…

非常郁闷,WinForm中正常显示的自定义控件无法在WebForm中正常显示!

我写了一个自定义控件(Win Control)&#xff0c;此控件在WinForm中运行正常&#xff0c;但在WebForm中无法显示(在WebForm中此控件并不显示为红叉&#xff0c;但是一个对象图标)。由于没有出现权限或安全方面的提示&#xff0c;因此我从头开始一行一行进行比对&#xff0c;最终…

在家过年这两天|多图

这两天收到了很多朋友的新年祝福&#xff0c;在这里回应下&#xff0c;希望看到这篇文章的朋友们新的一年快乐开心&#xff0c;在求学的人学有所成&#xff0c;在工作的朋友们功成名就&#xff0c;家人健康&#xff0c;吃喝不愁……祝你们㏠㏡㏢㏣㏤㏥㏦㏧㏨㏩㏪㏫㏬㏭㏮㏯㏰㏱…

两路归并排序

两路归并排序&#xff08;升序排列&#xff09; (平均/最差)时间复杂度O(NlogN) 将两个有序的单链表合并为一个有序的单链表&#xff0c;默认是按升序排列的。 合并操作是非常适合用递归来完成的一类操作&#xff0c;递归实现将会比迭代实现更加清晰且易于理解。 尽管如此&…

Eclipse下的项目管理插件介绍

前言 最近,一直学习开源项目的代码,难免会碰到各种版本管理器,作为一名在校大学生,学校的课程完全没提及到,靠着自己的摸索,走了不少弯路,写个列表,望对大家有所帮助.顺便提一下,这里只说客户端,至于服务端,自行根据提供的资料学习 CVS 这里eclipse自带就有,也有一段历史,现在的…

算命

今天大年初三&#xff0c;出了太阳变暖很多&#xff0c;我们带着家里的小朋友一起上街吃早餐。因为明天要去阳西&#xff0c;决定去外婆家看看&#xff0c;在超时买了点东西&#xff0c;走回车上刚好看到路边有算命先生&#xff0c;我就想着来计算一下。我先是问了记算一次多少…

back log

1*你应该备份日志 BACKUP LOG 数据库名 TO DISKc:\aalogbak WITH INIT,NO_TRUNCATE 这样你的日志清空也备份了&#xff0c;日志也清空了&#xff0c;你可以压缩了 在维护日志备份序列时&#xff0c;调度 BACKUP LOG 语句按间隔发生&#xff0c;以使事务日志不致增长到超过预期的…

java loadlibrary_java – System.loadLibrary不起作用.链中的第二个lib的UnsatisfiedLinkError...

我有通过JNI使用cpp共享库libclient.so的java程序Client.class.libclient.so构建为共享并使用cpp共享库libhttp.so.libclient.so和libhttp.so放在文件夹/ home / client / lib64中Client.class放在/ home / client / bin中客户端可以加载库> System.load和环境变量LD_LIBRAR…

tcp的滑动窗口

今天阅读了TCP中滑动窗口部分的内容&#xff0c;总结如下&#xff1a; 滑动窗口&#xff1a;又叫缓冲区&#xff0c;是两台主机间传送数据时的缓冲区。每台TCP/IP主机支持两个滑动窗口&#xff1a;一个用于接收数据&#xff0c;另一个用于发送数据。 窗口尺寸表示计算机可能缓…

嵌入式行业那些坑与出路

嵌入式的坑烧钱嵌入式的学习十分烧钱&#xff0c;这就让人有点望而却步。我是做DSP起步的&#xff0c;更是能体会到嵌入式绝对是一个拿钱搭梯子的学习行业。在我的学习过程中身边有不少的人投向了CS行业&#xff0c;也就是纯软件开发&#xff0c;比如网页、手机应用、数据库等。…

入行后第二份工作的一些感悟

这是我毕业后进入的第二家公司。也是我工作的第二个年头。转眼之间在新公司已经度过半年的时间了。内心还是有些许的感慨。 工作的内容和上家公司是差不多的&#xff0c;主要是做windows方面的基础架构和应用的维护&#xff0c;例如AD、exchange、lync、ISA、虚拟化等等&a…