java 并发 异步_Java高并发之同步异步

1、概念理解:

54a9c5f835384745dac135c5d7f45c01.png

2、同步的解决方案:

1).基于代码

synchronized 关键字

修饰普通方法:作用于当前实例加锁,进入同步代码前要获得当前实例的锁。

修饰静态方法:作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。

修饰代码块:指定加锁对象,对给定对象加锁,进入同步代码块前要获得给定对象的锁。

code1

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.thread;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;/*** 同步方法

*@authorAdministrator

**/

public class SynchronizedMethod implementsRunnable{//静态共享变量 i

static int i = 0;/*** 自增*/

public synchronized voidincrease(){

i++;

}

@Overridepublic voidrun() {for (int j = 0; j < 100; j++) {

increase();

}

}public static void main(String[] args) throwsInterruptedException {

SynchronizedMethod instance= newSynchronizedMethod();

ExecutorService executorService= Executors.newFixedThreadPool(2);for (int i = 0; i < 3; i++) {//同一实例,线程共享静态变量i//executorService.execute(instance);//不同实例,线程单独享有变量i,达不到同步目的

executorService.execute(newSynchronizedMethod());/*** 由于线程执行时间过短,在不同实例下,可能会得到类似于同步的结果。*/Thread.sleep(100);

}

executorService.shutdown();

System.out.println(i);//300

}

}

View Code

code2

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.thread;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;/*** 同步代码块

*@authorAdministrator

**/

public class SynchronizedCodeBlock implementsRunnable{//静态共享变量 i

static int i = 0;

@Overridepublic voidrun() {//同步进来的对象

synchronized(this){ //SynchronizedCodeBlock.class

for (int j = 0; j < 100; j++) {

i++;

}

}

}public static void main(String[] args) throwsInterruptedException {

SynchronizedCodeBlock instance= newSynchronizedCodeBlock();

ExecutorService executorService= Executors.newFixedThreadPool(2);for (int i = 0; i < 3; i++) {//executorService.execute(instance);

executorService.execute(newSynchronizedCodeBlock());

Thread.sleep(10);

}

executorService.shutdown();

System.out.println(i);//300

}

}

View Code

wait与notify运用

wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

notifyAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

code3

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.test;/*** 多线程实现 生产者-消费者模式

* 关键点:wait和notifyAll或者notify时机的运用,确保先生产后消费

*@authorAdministrator

**/

public classTest

{private static Integer count = 0; //数据仓库计数

private final Integer FULL = 5; //数据仓库最大存储量

private static String lock = "lock"; //锁标识

public static voidmain(String[] args)

{

Test t= newTest();new Thread(t.newProducer()).start();new Thread(t.newConsumer()).start();new Thread(t.newProducer()).start();new Thread(t.newConsumer()).start();

}//生产者

class Producer implementsRunnable

{

@Overridepublic voidrun()

{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 implementsRunnable

{

@Overridepublic voidrun()

{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();

}

}

}

}

}

View Code

volatile实现线程同步

原理:volatile保证不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,新值对其他线程来说是立即可见的,并且禁止进行指令重排序。

注意:volatile不保证原子性,凡是不是原子性的操作,都不能保证可见性,也即不能保证同步

应用:

1)对变量的写操作不依赖于当前值 类似 i++、i=j 等操作 不能对 i 用volatile。解决办法:类似操作增加 synchronized、Lock、AtomicInteger 保证原子性。

2)该变量没有包含在具有其他变量的不变式中

常用在多线程状态标志 flag、

ReentrantLock重入锁

重入锁:外层函数获取锁后,内层函数依然有获取该锁的代码,则重入锁无需再次获取锁,即可进入内层代码

code1

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.lock;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.locks.ReentrantLock;/*** 重入锁

* 外层函数获取锁后,内层函数依然有获取该锁的代码,则重入锁无需再次获取锁,即可进入内层代码

* ReentrantLock 和synchronized 都是 可重入锁

*@authorAdministrator

**/

public class ReentranLockTest implementsRunnable{public static ReentrantLock lock = newReentrantLock();public static int i = 0;

@Overridepublic voidrun() {for (int j = 0; j < 10; j++) {

lock.lock();//加锁

try{

i++;

}finally{

lock.unlock();//释放锁

}

}

}public static void main(String[] args) throwsInterruptedException {

ReentranLockTest test= newReentranLockTest();

ExecutorService executorService= Executors.newFixedThreadPool(2);for (int i = 0; i < 2; i++) {

executorService.execute(test);

Thread.sleep(1000);

}

executorService.shutdown();

System.out.println(i);

}

}

View Code

code2

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.lock;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;/*** 可中断的重入锁

* 条件中断等待

*@authorAdministrator

**/

public classInterruptiblyLockTest {public static Lock lock = newReentrantLock();public voidfunction(){

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) throwsInterruptedException {

InterruptiblyLockTest test= newInterruptiblyLockTest();//定义两个线程

Thread t0 = newThread() {public voidrun() {

test.function();

}

};

Thread t1= newThread() {public voidrun() {

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();//中断:只能中断处于等待锁的线程,不能中断已经获取锁的线程

}

}

View Code

code3

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.lock;importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.locks.ReentrantLock;/*** 尝试型锁

* 拒绝阻塞

*@authorAdministrator

**/

public classTryLockTest {public ReentrantLock lock = newReentrantLock();/*** tryLock

* 当前资源没有被占用,则tryLock获取锁

* 当前资源被当前锁占用,则tryLock返回true

* 当前资源被其他线程占用,则tryLock返回false

*@throwsInterruptedException*/

public void tryLockFunction() throwsInterruptedException{

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,可被中断

*

*@throwsInterruptedException*/

public void tryLockInterruptFunction() throwsInterruptedException{

String tName=Thread.currentThread().getName();

SimpleDateFormat format= new SimpleDateFormat("yyyy-MM-dd:hh:mm:ss");

System.out.println(tName+ "-开始尝试获取锁,当前时间:"+format.format(newDate()));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(newDate()));

}

}public static voidmain(String[] args) {

TryLockTest test= newTryLockTest();new Thread("Lock-Thread1") {public voidrun() {try{

test.tryLockFunction();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}.start();new Thread("Lock-Thread2") {public voidrun() {try{

test.tryLockFunction();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}.start();//Lock-Thread1-获取到锁了//Lock-Thread2-无法获取到锁//Lock-Thread1工作了3秒钟......//Lock-Thread1-释放锁

new Thread("LockInterrupt-Thread1") {public voidrun() {try{

test.tryLockInterruptFunction();

}catch(InterruptedException e) {

e.printStackTrace();

}

}

}.start();new Thread("LockInterrupt-Thread2") {public voidrun() {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-释放锁

}

}

View Code

code4

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packagecom.lock;importjava.util.concurrent.locks.ReentrantLock;/*** 公平锁

* 按时间先后获取锁

*@authorAdministrator

**/

public classFairLockTest {//创建一个公平锁

public static ReentrantLock lock = new ReentrantLock(true);public voidfairLockFunction(){while(true){try{

lock.lock();

System.out.println(Thread.currentThread().getName()+"获取到锁......");

}finally{

lock.unlock();

}

}

}public static voidmain(String[] args) {

FairLockTest test= newFairLockTest();

Thread t1= new Thread("线程1") {public voidrun() {

test.fairLockFunction();

}

};

Thread t2= new Thread("线程2") {public voidrun() {

test.fairLockFunction();

}

};

t1.start();

t2.start();

}//线程1获取到锁......//线程2获取到锁......//线程1获取到锁......//线程2获取到锁......//线程1获取到锁......//线程2获取到锁......//线程1获取到锁......//线程2获取到锁......

}

View Code

ThreadLocal创建线程间变量副本

final实现volatile可见性

通过final不可变性的特点,替代volatile的可见性。

参考博客:

2).基于数据库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值