Java高并发之同步异步
1、概念理解:
2、同步的解决方案:
1).基于代码
synchronized 关键字
修饰普通方法:作用于当前实例加锁,进入同步代码前要获得当前实例的锁。
修饰静态方法:作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。
修饰代码块:指定加锁对象,对给定对象加锁,进入同步代码块前要获得给定对象的锁。
code1
- package com.thread;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- /**
- * 同步方法
- * @author Administrator
- *
- */
- public class SynchronizedMethod implements Runnable{
- //静态共享变量 i
- static int i = 0;
- /**
- * 自增
- */
- public synchronized void increase(){
- i++;
- }
- @Override
- public void run() {
- for (int j = 0; j < 100; j++) {
- increase();
- }
- }
- public static void main(String[] args) throws InterruptedException {
- SynchronizedMethod instance = new SynchronizedMethod();
- ExecutorService executorService = Executors.newFixedThreadPool(2);
- for (int i = 0; i < 3; i++) {
- //同一实例,线程共享静态变量i
- // executorService.execute(instance);
- //不同实例,线程单独享有变量i,达不到同步目的
- executorService.execute(new SynchronizedMethod());
- /**
- * 由于线程执行时间过短,在不同实例下,可能会得到类似于同步的结果。
- */
- Thread.sleep(100);
- }
- executorService.shutdown();
- System.out.println(i); //
- }
- }
code2
- package com.thread;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- /**
- * 同步代码块
- * @author Administrator
- *
- */
- public class SynchronizedCodeBlock implements Runnable{
- //静态共享变量 i
- static int i = 0;
- @Override
- public void run() {
- //同步进来的对象
- synchronized(this){ //SynchronizedCodeBlock.class
- for (int j = 0; j < 100; j++) {
- i++;
- }
- }
- }
- public static void main(String[] args) throws InterruptedException {
- SynchronizedCodeBlock instance = new SynchronizedCodeBlock();
- ExecutorService executorService = Executors.newFixedThreadPool(2);
- for (int i = 0; i < 3; i++) {
- // executorService.execute(instance);
- executorService.execute(new SynchronizedCodeBlock());
- Thread.sleep(10);
- }
- executorService.shutdown();
- System.out.println(i); //
- }
- }
wait与notify运用
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。
notifyAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
code3
- package com.test;
- /**
- * 多线程实现 生产者-消费者模式
- * 关键点:wait和notifyAll或者notify时机的运用,确保先生产后消费
- * @author Administrator
- *
- */
- public class Test
- {
- private static Integer count = 0; //数据仓库计数
- private final Integer FULL = 5; //数据仓库最大存储量
- private static String lock = "lock"; //锁标识
- public static void main(String[] args)
- {
- Test t = new Test();
- new Thread(t.new Producer()).start();
- new Thread(t.new Consumer()).start();
- new Thread(t.new Producer()).start();
- new Thread(t.new Consumer()).start();
- }
- //生产者
- class Producer implements Runnable
- {
- @Override
- public void run()
- {
- for (int i = 0; i < 5; i++)
- {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- }
- synchronized (lock)
- {
- while (count == FULL)
- {
- try {
- lock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- count++;
- System.out.println(Thread.currentThread().getName() + "produce:: " + count);
- //唤醒lock锁上的所有线程
- lock.notifyAll();
- }
- }
- }
- }
- //消费者
- class Consumer implements Runnable
- {
- @Override
- public void run()
- {
- for (int i = 0; i < 5; i++)
- {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- }
- synchronized (lock)
- {
- //如果首次消费者竞争得到锁,进入后等待
- while (count == 0)
- {
- try {
- lock.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- count--;
- System.out.println(Thread.currentThread().getName()+ "consume:: " + count);
- lock.notifyAll();
- }
- }
- }
- }
- }
volatile实现线程同步
原理:volatile保证不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,新值对其他线程来说是立即可见的,并且禁止进行指令重排序。
注意:volatile不保证原子性,凡是不是原子性的操作,都不能保证可见性,也即不能保证同步
应用:
1)对变量的写操作不依赖于当前值 类似 i++、i=j 等操作 不能对 i 用volatile。解决办法:类似操作增加 synchronized、Lock、AtomicInteger
保证原子性。
2)该变量没有包含在具有其他变量的不变式中
常用在多线程状态标志 flag、
ReentrantLock重入锁
重入锁:外层函数获取锁后,内层函数依然有获取该锁的代码,则重入锁无需再次获取锁,即可进入内层代码
code1
- package com.lock;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * 重入锁
- * 外层函数获取锁后,内层函数依然有获取该锁的代码,则重入锁无需再次获取锁,即可进入内层代码
- * ReentrantLock 和synchronized 都是 可重入锁
- * @author Administrator
- *
- */
- public class ReentranLockTest implements Runnable{
- public static ReentrantLock lock = new ReentrantLock();
- public static int i = 0;
- @Override
- public void run() {
- for (int j = 0; j < 10; j++) {
- lock.lock(); //加锁
- try {
- i++;
- } finally {
- lock.unlock(); //释放锁
- }
- }
- }
- public static void main(String[] args) throws InterruptedException {
- ReentranLockTest test = new ReentranLockTest();
- ExecutorService executorService = Executors.newFixedThreadPool(2);
- for (int i = 0; i < 2; i++) {
- executorService.execute(test);
- Thread.sleep(1000);
- }
- executorService.shutdown();
- System.out.println(i);
- }
- }
code2
- package com.lock;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * 可中断的重入锁
- * 条件中断等待
- * @author Administrator
- *
- */
- public class InterruptiblyLockTest {
- public static Lock lock = new ReentrantLock();
- public void function(){
- String tName = Thread.currentThread().getName();
- try {
- System.out.println(tName + "-开始获取锁......");
- lock.lockInterruptibly();
- System.out.println("获取到锁了......");
- Thread.sleep(10000);
- System.out.println("睡眠10秒后,开始干活......");
- for (int i = 0; i < 5; i++) {
- System.out.println(tName + ":" + i);
- }
- System.out.println("活干完了......");
- } catch (Exception e) {
- System.out.println(tName + "-我好像被人中断了!");
- e.printStackTrace();
- }finally {
- lock.unlock();
- System.out.println(tName + "-释放了锁");
- }
- }
- public static void main(String[] args) throws InterruptedException {
- InterruptiblyLockTest test = new InterruptiblyLockTest();
- //定义两个线程
- Thread t0 = new Thread() {
- public void run() {
- test.function();
- }
- };
- Thread t1 = new Thread() {
- public void run() {
- test.function();
- }
- };
- String tName = Thread.currentThread().getName();
- System.out.println(tName + "-启动t0");
- t0.start();
- System.out.println(tName + "-等5秒,再启动t1");
- Thread.sleep(5000);
- System.out.println(tName + "-启动t1");
- t1.start();
- //t0先占据了锁还在睡眠
- System.out.println(tName + "-不等了,把t1中断掉!");
- t1.interrupt(); //中断:只能中断处于等待锁的线程,不能中断已经获取锁的线程
- }
- }
code3
- package com.lock;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * 尝试型锁
- * 拒绝阻塞
- * @author Administrator
- *
- */
- public class TryLockTest {
- public ReentrantLock lock = new ReentrantLock();
- /**
- * tryLock
- * 当前资源没有被占用,则tryLock获取锁
- * 当前资源被当前锁占用,则tryLock返回true
- * 当前资源被其他线程占用,则tryLock返回false
- * @throws InterruptedException
- */
- public void tryLockFunction() throws InterruptedException{
- String tName = Thread.currentThread().getName();
- if(lock.tryLock()){
- try {
- System.out.println(tName + "-获取到锁了");
- Thread.sleep(3000);
- System.out.println(tName + "工作了3秒钟......");
- } finally {
- lock.unlock();
- System.out.println(tName + "-释放锁");
- }
- }else{
- System.out.println(tName + "-无法获取到锁");
- }
- }
- /**
- * tryLock(long timeout, TimeUnit unit)
- * timeout时间内尝试请求锁,请求到了则返回true,可被中断
- *
- * @throws InterruptedException
- */
- public void tryLockInterruptFunction() throws InterruptedException{
- String tName = Thread.currentThread().getName();
- SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");
- System.out.println(tName + "-开始尝试获取锁,当前时间:"+format.format(new Date()));
- if(lock.tryLock(3,TimeUnit.SECONDS)){
- try {
- System.out.println(tName + "-获取到锁了");
- Thread.sleep(5000);
- System.out.println(tName + "工作了3秒钟......");
- } finally {
- lock.unlock();
- System.out.println(tName + "-释放锁");
- }
- }else{
- System.out.println(tName + "-无法获取到锁");
- System.out.println(tName + "-结束尝试获取锁,当前时间:"+format.format(new Date()));
- }
- }
- public static void main(String[] args) {
- TryLockTest test = new TryLockTest();
- new Thread("Lock-Thread1") {
- public void run() {
- try {
- test.tryLockFunction();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }.start();
- new Thread("Lock-Thread2") {
- public void run() {
- try {
- test.tryLockFunction();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }.start();
- //Lock-Thread1-获取到锁了
- //Lock-Thread2-无法获取到锁
- //Lock-Thread1工作了3秒钟......
- //Lock-Thread1-释放锁
- new Thread("LockInterrupt-Thread1") {
- public void run() {
- try {
- test.tryLockInterruptFunction();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }.start();
- new Thread("LockInterrupt-Thread2") {
- public void run() {
- try {
- test.tryLockInterruptFunction();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }.start();
- //LockInterrupt-Thread2-开始尝试获取锁,当前时间:2019-01-17:05:12:32
- //LockInterrupt-Thread1-开始尝试获取锁,当前时间:2019-01-17:05:12:32
- //LockInterrupt-Thread2-获取到锁了
- //LockInterrupt-Thread1-无法获取到锁
- //LockInterrupt-Thread1-结束尝试获取锁,当前时间:2019-01-17:05:12:35
- //LockInterrupt-Thread2工作了3秒钟......
- //LockInterrupt-Thread2-释放锁
- }
- }
code4
- package com.lock;
- import java.util.concurrent.locks.ReentrantLock;
- /**
- * 公平锁
- * 按时间先后获取锁
- * @author Administrator
- *
- */
- public class FairLockTest {
- //创建一个公平锁
- public static ReentrantLock lock = new ReentrantLock(true);
- public void fairLockFunction(){
- while(true){
- try {
- lock.lock();
- System.out.println(Thread.currentThread().getName()+"获取到锁......");
- } finally {
- lock.unlock();
- }
- }
- }
- public static void main(String[] args) {
- FairLockTest test = new FairLockTest();
- Thread t1 = new Thread("线程1") {
- public void run() {
- test.fairLockFunction();
- }
- };
- Thread t2 = new Thread("线程2") {
- public void run() {
- test.fairLockFunction();
- }
- };
- t1.start();
- t2.start();
- }
- //线程1获取到锁......
- //线程2获取到锁......
- //线程1获取到锁......
- //线程2获取到锁......
- //线程1获取到锁......
- //线程2获取到锁......
- //线程1获取到锁......
- //线程2获取到锁......
- }
ThreadLocal创建线程间变量副本
参考博客:聊一聊Spring中的线程安全性
final实现volatile可见性
通过final不可变性的特点,替代volatile的可见性。
参考博客:
https://blog.csdn.net/javazejian/article/details/72828483
https://www.cnblogs.com/duanxz/p/3709608.html?utm_source=tuicool&utm_medium=referral
http://www.cnblogs.com/duanxz/p/5066726.html
2).基于数据库
Java高并发之同步异步的更多相关文章
- Java高并发之锁优化
本文主要讲并行优化的几种方式, 其结构如下: 锁优化 减少锁的持有时间 例如避免给整个方法加锁 public synchronized void syncMethod(){ othercode1(); ...
- java高并发之线程池
Java高并发之线程池详解 线程池优势 在业务场景中, 如果一个对象创建销毁开销比较大, 那么此时建议池化对象进行管理. 例如线程, jdbc连接等等, 在高并发场景中, 如果可以复用之前销毁的对 ...
- java高并发之锁的使用以及原理浅析
锁像synchronized同步块一样,是一种线程同步机制.让自Java 5开始,java.util.concurrent.locks包提供了另一种方式实现线程同步机制——Lock.那么问题来了既然都 ...
- Java高并发之线程基本操作
结合上一篇同步异步,这篇理解线程操作. 1.新建线程.不止thread和runnable,Callable和Future了解一下 package com.thread; import java.tex ...
- Java高并发之设计模式
本文主要讲解几种常见并行模式, 具体目录结构如下图. 单例 单例是最常见的一种设计模式, 一般用于全局对象管理, 比如xml配置读写之类的. 一般分为懒汉式, 饿汉式. 懒汉式: 方法上加synchr ...
- 1.6 JAVA高并发之线程池
一.JAVA高级并发 1.5JDK之后引入高级并发特性,大多数的特性在java.util.concurrent 包中,是专门用于多线程发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发 ...
- Java 高并发之魂
前置知识 了解Java基本语法 了解多线程基本知识 知识介绍 Synchronized简介:作用.地位.不控制并发的后果 两种用法:对象锁和类锁 多线程访问同步方法的7种情况:是否是static.Sy ...
- Java高并发之从零到放弃
前言 本篇主要讲解如何去优化锁机制或者克服多线程因为锁可导致性能下降的问题 ThreadLocal线程变量 有这样一个场景,前面是一大桶水,10个人去喝水,为了保证线程安全,我们要在杯子上加锁导致大家 ...
- Java高并发之无锁与Atomic源码分析
目录 CAS原理 AtomicInteger Unsafe AtomicReference AtomicStampedReference AtomicIntegerArray AtomicIntege ...
随机推荐
- android finish和system.exit(0)的区别
finish是Activity的类,仅仅针对Activity,当调用finish()时,只是将活动推向后台,并没有立即释放内存,活动的资源并没有被清理:当调用System.exit(0)时,杀死了整个 ...
- MVC之ViewData.Model
在MVC中前台Razor视图呈现数据的方式不止一种.举个简单的Demo,我们要把用户信息呈现给人民. 一.ViewData.Model的使用,先简单写一下Razor @model User---- ...
- 修复kindEditor点击加粗, 内容焦点跳动的问题
大概1560~1569行 pos : function() { var self = this, node = self[0], x = 0, y = 0; if (node) { if (node. ...
- CSS Grid 布局学习笔记
CSS Grid 布局学习笔记 好久没有写博客了, MDN 上关于 Grid 布局的知识比较零散, 正好根据我这几个月的实践对 CSS Grid 布局做一个总结, 以备查阅. 1. 基础用法 Grid ...
- 使用js来执行全屏
当用户按下F11事件,浏览器为触发自身全屏功能,这个过程我们一般是不可控制的,即使是监听了F11的键盘事件,退出全屏的时候,我们也捕捉不到退出全屏触发的事件.所以,我们就用程序自己去实现F11的功能, ...
- android libs库中的armeabi-v7a,armeabi和x86
以下内容转载于:http://blog.csdn.net/liumou111/article/details/52949156 1.区别: 这三者都表示的是CPU类型,早期的Android系统几乎只支 ...
- selenium中Alter等弹出对话框的处理
昨天使用selenium做自动化测试,发现部分页面会弹出alert对话框,找了写资料,大概的意思就是要给弹出的对话框做出相应,不然,后续的处理会失败. _driver.SwitchTo().Alert ...
- 我的ORM框架
任何系统的基础,都可以算是各种数据的增删改查(CRUD).最早操作数据是直接在代码里写SQL语句,后来出现了各种ORM框架.C#下的ORM框架有很多,如微软自己的Entity Framework.第三 ...
- Eclipse下JRebel的安装和基本使用
JRebel有什么用? 做Java Web开发,一个很头疼的事情是,修改了一个类以后,Tomcat必须重新启动. 工程规模小还好说,如果规模大了,重启一次动不动就是一分多钟.那么频繁重启就会导致大量的 ...
- Vue.js-创建Vue项目(Vue项目初始化)并不是用Webstrom创建,只是用Webstrom打开
我犯的错误:作为vue小白,并不知道还要单独去创建初始的vue项目,于是自己在webstrom中建了一个Empty Project, 在其中新增了一个js文件,就开始import Vue from “ ...