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 ...
随机推荐
- HDU 4612——Warm up——————【边双连通分量、树的直径】
Warm up Time Limit:5000MS Memory Limit:65535KB 64bit IO Format:%I64d & %I64u Submit Stat ...
- C# DialogResult的用法
在程序中,经常会弹出一个对话框来让用户填写一些信息,填写完成后,当用户点击“确定”按钮后,在主窗体中进行其他的处理.比如一个简单的例子,在主窗体中有一个菜单,是“增加用户”,当点击这个菜单之后,我们需 ...
- CSS基础必备盒模型及清除浮动
盒模型 盒模型是有两种标准的,一个是标准模型,一个是IE模型. css如何设置两种模型 这里用到了CSS3 的属性 box-sizing /* 标准模型 */ box-sizing:content-b ...
- vue本地和线上环境(域名)配置
vue本身为运行脚手架项目自家搭载了一个nodejs后台环境,本地可通过proxyTable来处理跨域问题,但是上线(或生产环境)之后改域名真是一件麻烦的事情,所以进行一些配置. config/ind ...
- Android - 通过真实案例学习解内存泄漏问题,最终发现Android原生Bug
作为一个Android新手小白,刚到新公司,最近的工作就是在学习解各类Bug.转型之初,面临各种新知识,会有压力,但是学习的过程是快乐的. 上周刚遇上一类bug,就是应用的内存泄漏问题.最终通过前辈的 ...
- 如何更换vim-airline的theme
仓库位置: 点我直达 (主题以前是和airline在同个仓库的,现在独立出来了) 这些内置的这些主题,可以直接使用,方法是在 “.vimrc”文件中写 let g:airline_theme=&quo ...
- 2017.10.28 QB模拟赛 —— 下午
题目链接 T1 按x值排序 遇到第二种牌插入 遇到第一种牌 查询<=y 的最小值 删除他 splay multiset cys大佬说 multiset就是不去重的set, #include &l ...
- April 15 2017 Week 15 Saturday
Attitude is a little thing that makes a big difference. 小态度,大不同. Attitudes can make a big difference ...
- React怎么创建.babelrc文件
在windows环境下做react开发其实是一件非常让人头疼的事,强烈建议使用Mac或者是Linux系统,否则真的是自己挖坑自己跳了. 不过,这里还是给大家说说如何在windows环境下新建一个.ba ...
- *521. Longest Uncommon Subsequence I (bit manipulation 2^n)
Given a group of two strings, you need to find the longest uncommon subsequence of this group of two ...