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高并发之同步异步的更多相关文章

  1. Java高并发之锁优化

    本文主要讲并行优化的几种方式, 其结构如下: 锁优化 减少锁的持有时间 例如避免给整个方法加锁 public synchronized void syncMethod(){ othercode1(); ...

  2. java高并发之线程池

    Java高并发之线程池详解   线程池优势 在业务场景中, 如果一个对象创建销毁开销比较大, 那么此时建议池化对象进行管理. 例如线程, jdbc连接等等, 在高并发场景中, 如果可以复用之前销毁的对 ...

  3. java高并发之锁的使用以及原理浅析

    锁像synchronized同步块一样,是一种线程同步机制.让自Java 5开始,java.util.concurrent.locks包提供了另一种方式实现线程同步机制——Lock.那么问题来了既然都 ...

  4. Java高并发之线程基本操作

    结合上一篇同步异步,这篇理解线程操作. 1.新建线程.不止thread和runnable,Callable和Future了解一下 package com.thread; import java.tex ...

  5. Java高并发之设计模式

    本文主要讲解几种常见并行模式, 具体目录结构如下图. 单例 单例是最常见的一种设计模式, 一般用于全局对象管理, 比如xml配置读写之类的. 一般分为懒汉式, 饿汉式. 懒汉式: 方法上加synchr ...

  6. 1.6 JAVA高并发之线程池

    一.JAVA高级并发 1.5JDK之后引入高级并发特性,大多数的特性在java.util.concurrent 包中,是专门用于多线程发编程的,充分利用了现代多处理器和多核心系统的功能以编写大规模并发 ...

  7. Java 高并发之魂

    前置知识 了解Java基本语法 了解多线程基本知识 知识介绍 Synchronized简介:作用.地位.不控制并发的后果 两种用法:对象锁和类锁 多线程访问同步方法的7种情况:是否是static.Sy ...

  8. Java高并发之从零到放弃

    前言 本篇主要讲解如何去优化锁机制或者克服多线程因为锁可导致性能下降的问题 ThreadLocal线程变量 有这样一个场景,前面是一大桶水,10个人去喝水,为了保证线程安全,我们要在杯子上加锁导致大家 ...

  9. Java高并发之无锁与Atomic源码分析

    目录 CAS原理 AtomicInteger Unsafe AtomicReference AtomicStampedReference AtomicIntegerArray AtomicIntege ...

随机推荐

  1. PHP函数库(core)

    数组函数: array_change_key_case — 返回字符串键名全为小写或大写的数组 array_change_key_case() 将 input 数组中的所有键名改为全小写或大写.改变是 ...

  2. .NET面试题1

    1. const和readonly有什么区别? const关键字用来声明编译时常量,readonly用来声明运行时常量.都可以标识一个常量,主要有以下区别: 1.初始化位置不同.const必须在声明的 ...

  3. PHP运行机制

    PHP运行机制: 访问html文件:访问的域名à解析成IP地址(hosts文件,dns)à找到服务器àapache拿到html文件à返回给浏览器à浏览器解析html内容 访问php文件:apache拿 ...

  4. IsPostBack详解

    1.IsPostBack<只需要加载一次的代码放在if(!IsPostBack)中> 今天在最开始定义了全局变量取得radiobuttonlist中得到的value,但是因为autopos ...

  5. 树莓派WLAN连接PC(不通过路由器)

    上一篇博文捣鼓了一下树莓派直连线连接PC.吃完午饭心血来潮,树莓派既然能用直连线连接PC,曾经也试过拿PC当作热点,为何不尝试一下用WLAN将树莓派与PC互连呢?果断搞起. 首先,我当前笔记本是用WL ...

  6. android studio gradle统一管理版本

    创建config.gradle ext { android = [ compileSdkVersion : 26, buildToolsVersion : "26.0.2", mi ...

  7. u-boot分析(八)----串口初始化

    u-boot分析(八) 上篇博文我们按照210的启动流程,分析到了内存初始化,今天我们继续按照u-boot的启动流程对串口的初始化进行分析. 今天我们会用到的文档: 1.        2440芯片手 ...

  8. Azure 7 月新公布

    Azure 7月新发布:Cosmos DB,事件中心捕捉功能,Hybrid Connections,流量管理器快速故障转移功能. 您现有的 DocumentDB 资源现已作为 Azure 门户上 Az ...

  9. Linux命令之添加权限Chmod的使用

    chmod是change mode的缩写,是修改文件权限的一个命令: 一个文件分别有三组权限:用户拥有者,用户组 第一个横杆-表示文件,如果是d表示目录.还有可能是l,表示链接. 第一组(rw-)表示 ...

  10. Mercurial (hg)

    附上两个站点: http://z42.readthedocs.org/zh/latest/devtools/hg.html http://bucunzai.net/hginit/ Mercurial( ...