并发编程

java并发编程

我的未来我决定 提交于 2020-11-22 13:47:49
一、 volatile 基本介绍 Java 语言提供了一种稍弱的同步机制,即 volatile 变量.用来确保将变量的更新操作通知到其他线程,保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新. 当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的. volatile 变量对所有线程是立即可见的,对 volatile 变量所有的写操作都能立即反应到 其他线程之中,换句话说:volatile 变量在各个线程中是一致的。 但是volatile并不是线程安全的。 volatile关键字能保证可见性,可见性只能保证每次读取的是最新的值;但是voliate没法保证对变量的操作的原子性。 二、举例说明 /** * * @author Yuanyuan */ public class Counter { public volatile int inc = 0; //一个线程执行increase的时候能保证得到了最新的当前值,但还没有执行自增操作,该线程就有可能被阻塞,此时其他线程也得到了这个最新值,执行了自增操作,这样之前那个阻塞的线程执行时就出错了。 public void increase() { System.out.println(inc); inc++; } public static void main(String[] args) { final

关于java并发编程的一些概念及策略

谁都会走 提交于 2020-04-14 01:32:02
【今日推荐】:为什么一到面试就懵逼!>>> 最近抽出了点时间,把java并发编程的一些概念和策略总结了一下: 1. 同一个程序中的多个线程可以被同时调度到多个 CPU 上(利用这一点通常能提高 cpu 的使用率) 2. 多线程运用的例子: RMI 、 Servlet 、 GUI (通常情况下: GUI 对象都只能在实事件线程中访问且 GUI 的对象是被封闭在 单个线程当中)、 Timer 等 3. 只有当类中仅包含自己的状态时,线程安全类才是有意义的 4. 在一定条件下,可以安全地放宽状态变量的封装性 5. 同步术语: sychronized 、 volatile 类型的变量、显式锁、原子变量 (concurrent 包中) 6. 最常见的竞态条件:先检查后执行( check-and-act ),读取 -- 修改 -- 写入 7. 内置锁 : 可重入(可重复获取相同的锁) 8. 在构造方法中可以创建线程,但最好不要启动线程,以防止启动的线程访问未完全构造的 this 引用 9. 构造方法中调用非 private 和 final 方法 (即有可能被复写的方法) 时 ,也会导致 this 引用逸出 10. 线程封闭的三种方式: Ad-hoc 线程封闭、栈封闭、 ThreadLocal 类 11. final 域(引用不指向可变对象的情况下)是线程安全的 12. 安全发布对象的常用模式:

java并发编程——锁机制

一世执手 提交于 2020-04-11 14:21:09
第一部分:synchronized和volatile 锁机制用来保护对象的一致性以及操作的原子性,是实现线程安全的重要手段。线程安全涉及到对象两个重要的状态:共享性和可变性。如果对象是不可变的、线程私有的那么它一定是线程安全的。所以说,只有在共享的、可变的对象上面进行操作时才需要加锁,以保障线程安全。volatile和synchronized是java 5.0之前最早协调对象共享的机制。下面我们将分别介绍他们: synchronized synchronized用来形容方法或者代码块,是java提供的最早的锁机制,支持重入锁。关于synchronized的详细解析文章有很多,这里列举几个注意事项: 第一,使用synchronized关键字时一定要尽可能的缩小范围,尽可能的在方法块里需要锁的地方使用,而不是直接用来修饰整个方法。这需要我们对方法里面的操作进行分析,哪些需要加锁,哪些不需要加锁,只在需要锁的地方加锁,这样即可以提高程序的效率,同时开放调用方法也减少了线程安全的隐患。 第二,synchronized提供的锁机制是粗粒度的,当有线程访问当前对象的synchronized方法或代码块时,其他线程只能等待当前操作结束才可以访问。这听上去似乎存在一定的性能问题,但java 6.0以后synchronized在并发环境下性能得到了大幅提升

java并发编程(五): 任务执行

只谈情不闲聊 提交于 2020-01-07 14:05:58
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 任务执行: 大多数并发应用程序都是围绕" 任务执行 "来构造的:任务通常是一些 抽象的 且 离散的 工作单元。 在线程中执行任务: 理想情况下,各个任务之间是 相互独立 的:任务并不依赖其他任务的 状态 , 结果 或 边界效应 。 串行地执行任务: /** * 串行处理请求: * 简单正确,但性能低下 */ public class SingleThreadWebServer { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(80); boolean listening = true; while (listening){ Socket connection = server.accept(); //阻塞等待客户端连接请求 handlerRequest(connection); } server.close(); } ... } 显示地为任务创建线程: /** * 为每一个用户请求创建一个线程为其服务 */ public class ThreadPerTaskWebServer { public static void main(String[] args)

java并发编程——性能和扩展性

夙愿已清 提交于 2019-12-17 23:33:18
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 第一部分:对性能的思考 并发编程的最主要目的是提高程序的运行性能,线程可以使程序更加充分的利用系统的可用处理能力,从而提高系统的资源利用率。然而使用多线程时也会引入额外的开销,这些开销包括:线程之间的协调(加锁,内存同步等)、增加的的上下文切换、线程的创建和销毁和线程的调度等等。如果过度以及不恰当的使用线程,这些开销甚至会抵消由于提高吞吐量、计算能力带来的性能提升。一个设计糟糕的多线程程序其性能可能比相同功能的串行程序效率还低。 提升性能意味着用更少的资源做更多的事情。资源的范围很广,比如CPU,内存,网络带宽,IO,磁盘空间等等。当操作性能由于某种特定的资源而受到限制时,我们通常称为资源密集型操作,比如CPU密集型等等。 要想通过并发来获得良好的性能,需要努力做好两件事:要有效的利用现有的资源,以及新的处理资源出现时程序能够有效的利用新增的资源。从性能监视的视角来看,CPU需要尽可能保持忙碌状态(当然这不意味着把CPU用在一些无用的计算上)。 应用程序的性能可以通过多个指标来衡量,比如一些指标(服务时间,等待时间)用来衡量运行速度,另一些指标(生产量、吞吐量)来衡量处理能力。因此,“多快”、“多少”是性能优化的两个不同方向,它们相互独立,有时甚至是互相矛盾的。因此,在优化之前必须要先确保以下几点: 第一

再深一点,理解线程的join方法

孤者浪人 提交于 2019-12-09 11:11:11
配图:曲径通幽 讲真,如果不是被面试官吊打,join()方法也还不会引起我的重视。因为,工作中确实没有使用过它。 现在,对它来个刨根问底。 join()方法的作用 在写这篇文章之前,我对join的理解只停留在字面意思“把指定线程加入到当前线程”。 再来看官方怎么解释的: //Waits for this thread to die. public final void join() throws InterruptedException { join(0); } “Waits for this thread to die.”,也就是等着join()方法所属的 线程死亡(run方法执行完毕正常结束或线程异常死亡)。 下面举个例子,证实这个说法。 举个栗子 import static java.lang.System.out; public class JoinTest { public static void main(String args[]) throws InterruptedException{ String threadName = Thread.currentThread().getName(); out.println(threadName + " is Started"); Thread th1 = new FooThread(); th1.start(); th1

java并发编程——线程池和Executor介绍

孤人 提交于 2019-12-04 20:26:02
第一部分:概述 早期的应用程序大多是单线程串行执行的,虽然程序的任务边界清晰有序,但是执行的效率却很低,尤其是执行花费时间较长的操作,会导致大量的等待和堆积。为了提高程序的执行效率和吞吐量,我们很自然的会想到多线程,即为每个任务都新建一个独立的线程,这样就极大地提高了程序的执行效率。但事实上多线程也会带来很多问题。比如大量的创建线程,这本身就会消耗很多的资源,尤其是内存,当创建的线程数量超过服务器能够承受的极限时,内存溢出是在所难免的;比如还有其他稳定性问题,以及多线程造成的程序调用和管理的混乱。所以,综上所述,我们需要一个介于两者之间的工具,既可以创建大量的线程来提高程序的并发性和吞吐量,同时又可以有序的管理这些线程,能够可控。而Executor接口和线程池技术就是在这种背景下应运而生的。下面分别将这两种常用的并发技术做以介绍和总结。 第二部分:Executor和ExecutorService接口介绍 java.util.coucurrent包下面为我们提供了丰富的并发工具,Executor和ExecutorService接口就是其中比较重要的两个。 Executor接口介绍 public interface Executor{ void execute(Runnable command); } 以上是Executor接口的代码,可以看出这个借口非常简单,就只有一个execute

什么是线程安全?

冷暖自知 提交于 2019-12-04 18:33:05
给“线程安全”下定义是件非常棘手的事儿。随便Google一下,就能得到成千上万像这样的定义: 1.“线程安全”的代码是指在多线程同时执行的情况下,依然能正常工作的代码。 2.一段代码,如果在多线程同时执行的情况下,能以一种安全的方式操作共享数据结构,它就是线程安全的。 还有很多类似的定义。 你不觉着类似上面这种定义非但没有传达出有用的信息,甚至让自己更加迷惑吗?尽管这样,这些定义还是被大家无奈的接受了,因为它并没有错。只是,他们没能提供任务实质性的帮助或见解。 我们怎么区别“线程安全”的类和不安全的类?甚至说“安全”到底什么意思? 在线程安全中,什么是“正确性”? 任何对“线程安全”的合理定义,其核心都是在说“正确性”的概念。所以在理解线程安全之前,我们先来搞懂什么是“正确性”。 正确性意味着一个类要符合它的规范 一个好的类规范会明确规定出类在某个时刻的状态,以及对它进行一些操作后的后置条件(postcondition)。但是,通常我们并不能为我们的类提供充分的规范说明,那我们怎么知道他们是否正确执行了?我们并不能知道,但是这并不能阻止我们去使用它,一旦我们说服了自己“这些代码能正确工作”。这种“代码信任”就非常接近我们要说的“正确性”。 现在我们可以给“线程安全”下一个不那么绕的定义: 一个类在多线程并发访问时仍能保证行为的正确性,那么它就是线程安全的类。

java并发编程

吃可爱长大的小学妹 提交于 2019-12-03 05:54:22
1. ReentrantLock拥有与Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候。 线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定, 如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断 如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情 ReentrantLock获取锁定有三种方式: a) lock() , 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁 b) tryLock() , 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false; c) tryLock(long timeout, TimeUnit unit) , 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false; d) lockInterruptibly :如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断 2. synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常

并发编程笔记二:synchronized锁住了谁?

点点圈 提交于 2019-12-01 04:44:45
在并发编程中要使用到关键字 synchronized ,当我们用 synchronized 关键字修饰一个方法时,代表着一个锁(Lock),那么这个锁的对象是什么,也就是它锁住了谁? synchronized 的使用情况大概就是下面几种: synchronized修饰非静态方法 synchronized修饰静态方法 同步代码块的synchronized (this) 同步代码块的synchronized (非this对象) 同步代码块的synchronized (类.class) 实际上,synchronized修饰非静态方法、同步代码块的synchronized (this)用法和synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。 synchronized修饰静态方法以及同步代码块的synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。 看下面代码: public class MultiThread { private static int num = 0; /** static */ public synchronized void printNum(String tag){ try { if(tag.equals("a")){ num = 100; System.out