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. The function getUserId must be used with a prefix when a default namespace is not specified 解决办法

    The function getUserId must be used with a prefix when a default namespace is not specified 解决方法: 1. ...

  2. Chrome谷歌浏览器中js代码Array.sort排序的bug乱序解决办法

    [现象] 代码如下: var list = [{ n: "a", v: 1 }, { n: "b", v: 1 }, { n: "c", v ...

  3. bundle绑定资源表

    1.注册绑定资源表 在application_Start函数中: (注意不要加拓展名,否则压缩时出问题) BundleTable.Bundles.Add(new ScriptBundle(" ...

  4. Spring IOC + AOP 的实现

    Spring思想很不错,尽量减少侵入式编程.现在了解到的Spring提供的功能有,DI,IOC,数据库操作,AOP,MVC.针对DI,AOP写了一些小DEMO PS:AOP真的很棒 代码参考:< ...

  5. The thirteen day

    Well begun is hanlf done 良好的开端是成功的一半.(此句是省略句,Something that is well begun is something that is half ...

  6. 通过adb获取应用的Activity堆栈信息

    获取所用应用 adb shell dumpsys activity 获取自己的应用 adb shell dumpsys activity | grep 应用的package 获取处于栈顶的activi ...

  7. Vue.js-项目目录结构解析

    1.Vue初始化项目目录如下: 2.目录各项含义如下:

  8. OJ网站

    没事做做题是打发时间的好办法,还能练习下思维,效益很不错,但就是耗时 就选了3个oj,多了眼花缭乱 https://www.vijos.org/ http://uoj.ac/ https://leet ...

  9. 静态库是.o文件的集合与弱符号

    静态库是.o文件的集合. 静态库与弱符号的概念相关联. 在生成库文件时,不做强符号检查.

  10. c#无限循环

    for( ; ; ) 最快的 while(true) while(1)             ?好像也是不过就是扫到的 public bool a= true; 中断一个循环while(a) a=f ...