java多线程与并发_Java多线程与并发

1. volatitle

volatitle对共享变量进行同步。在写入volatitle变量值之后,CPU缓存中的内容会被协会主存,再读取volatitle变量值时,缓存值为失效状态,然后重新从主存读取已改变过的值。

2. synchronized 关键字

所有的Java对象都有一个与之关联的监视器对象,允许在该监视器上进行加锁和解锁

这里一定要理解清楚,我们加锁的是监视器对象,而不是代码code

synchronized静态方法 监视器对象是所在Java类对应的Class

synchronized实例对象方法 监视器对象是当前对象实例

synchronized代码块 代码块声明中的对象

2.1 synchronized方法

2.1.1. synchronized关键字的继承性

synchronized关键字是不能继承的,父类的 synchronized方法在子类中并不是synchronized,子类需要显式地为某个方法加synchronized,以变成同步方法

2.1.2. synchronized实例对象方法

synchronized method(){}的监视器对象是这个实例对象,加锁的对象不是这个方法,而是实例对象

public class Foo {

/** * 加锁的监视器对象是class Foo 的 实例对象 Foo foo = new Foo()后的foo * 而不是这个方法mothodA */

public synchronized void mothodA()

{}

public synchronized void mothodB()

{}

}

有多个线程去访问 foo.mothodA() 时,同时只有一个线程能访问foo的mothodA()方法

一个类的实例对象有多个synchronized的方法时,只要一个线程访问了其中一个synchronized方法,其它线程就不能访问这个对象中的任何一个synchronized方法

不同实例对象间的synchronized方法调用时互不影响的

Foo foo1 = new Foo();

Foo foo2 = new Foo();

不同的线程分别访问foo1、foo2中的synchronized mothodA()方法是互不影响的,因为它们的监视器对象分别是foo1、foo2,同一个监视器对象才会阻塞同步

2.1.3 synchronized static 静态方法

synchronized static staticMethodA()的监视器对象是Foo.class类,所有访问这个类的静态同步方法的线程,都在同一个 Foo.class上加锁和解锁,所以对所有线程中的类实例对象的同步起作用。

class Foo

{

public synchronized static methodA();

public synchronized static staticMethodA();

}

一个线程里调用了Foo.staticMethodA(),会对其它线程调用foo.methodA()造成同步

2.2 synchronized代码块

多个并发线程访问一个对象的synchronized(this)同步代码块时,同一时间只有一个线程执行

当一个线程访问一个对象的synchronized(this)同步代码块时,其它线程仍然可以访问这个对象的非synchronized(this)代码块,而对对象中其它所有的synchronized(this)同步代码块的访问都将被阻塞

class Foo

{

public void methodA()

{

/** * 加锁对象是 实例对象 * this 关键字代表实例对象本身 */

synchronized (this) {

}

}

}

public class Foo extends Thread {

private int val;

//全局

private static Object lock = new Object();

public Foo(int v)

{

val = v;

}

@Override

public void run()

{

printVal(val);

}

public void printVal(int v)

{

synchronized (lock)

{

while(true)

System.out.println(v);

}

}

}

3. Object类的wait、notify、notifyAll

/** * 以以下代码顺序执行的方式就能确保异步执行的过程正确的获取到looper, * 当前线程里调用 new Worker(),如果looper还未创建调用线程就陷入wait状 * 态,构造函数里启动另一线程,创建looper后会唤醒new Worker()的调用线 * 程,这时new Worker()才执行完,接着执行下面的getLooper()就能正常获取 *

 * mAlbumArtWorker = new Worker("album art worker"); * mAlbumArtHandler = new AlbumArtHandler(mAlbumArtWorker.getLooper()); * 
*/

public class Worker implements Runnable {

private final Object mLock = new Object();

private Looper mLooper;

Worker(String name)

{

//调用线程里构造函数启动另一个线程

Thread t = new Thread(null,this,name);

t.setPriority(Thread.MIN_PRIORITY);

t.start();

synchronized (mLock)

{

//如果当前looper对象未创建

while(mLooper == null)

{

try

{

//调用构造函数的线程wait,并释放监视对象mLock持有的锁

mLock.wait();

} catch (InterruptedException ex)

{}

}

}

}

public Looper getLooper()

{

return mLooper;

}

@Override

public void run()

{

//对检视对象mLock加锁

synchronized (mLock)

{

Looper.prepare();

mLooper = Looper.myLooper();

//唤醒监视对象mLock上等待的所有线程,如果调用构造函数的线程在wait状态,将被唤醒

mLock.notifyAll();

}

Looper.loop();

}

public void quit()

{

mLooper.quit();

}

}

4.高级实用工具

4.1 java.util.concurrent.locks中的API

锁可在对象之间传递,因此使用更灵活

4.2 java.util.concurrent.Semaphore信号量

可以创建一个new Semaphore(0)零个许可的信号量作为一个阻塞点,另一个工作线程处理完一定的工作后release()释放一个许可出来,让前面阻塞的线程继续执行

4.3 java.util.concurrent.CountDownLatch倒数闸门

4.4 java.util.concurrent.CyclicBarrier循环屏障

4.5 java.util.concurrent.Exchanger对象交换器

适用于两个线程需要交换数据的场景。

只能有2个线程交换数据

exchange是交换点,另一线程未到达则本线程在此等待

各自线程exchange函数的返回值是另一线程exchange的参数值

public class FillAndEmpty {

Exchanger exchanger = new Exchanger();

DataBuffer initialEmptyBuffer = ... a made-up type

DataBuffer initialFullBuffer = ...

class FillingLoop implements Runnable

{

public void run()

{

//生成一个empty 的空缓冲区

DataBuffer currentBuffer = initialEmptyBuffer;

try {

while (currentBuffer != null) {

//向空缓冲区填充数据

addToBuffer(currentBuffer);

if (currentBuffer.isFull())

{

/** * 1.到达交换点,如果另一个线程还没有到exchanger.exchange交换点,则在此阻塞等待 * 2.这里exchanger.exchange 返回的数据,就是另一线程到达exchanger.exchange(dataA)时 * 传递的dataA,并把自己exchanger.exchange(dataB)传递的dataB传递给另一线程的exchanger.exchange * 作为返回值 */

currentBuffer = exchanger.exchange(currentBuffer);

//另一线程到达exchanger.exchange后,彼此线程安全的交换数据exchanger.exchange()函数返回后继续执行

}

}

} catch (InterruptedException ex) { ...handle ...}

}

}

class EmptyingLoop implements Runnable

{

public void run()

{

DataBuffer currentBuffer = initialFullBuffer;

try {

while (currentBuffer != null) {

takeFromBuffer(currentBuffer);

//缓冲区数据是空的

if (currentBuffer.isEmpty())

{

/** * 1.进入交换点,如果填充线程未到达交换点,则再次阻塞,等待填充线程到达时继续执行 * 2.exchanger.exchange(currentBuffer) 把自己空的缓冲区作为参数传递给填充线程,填充 * 线程exchanger.exchange的返回值就是本线程(exchanger.exchange(dataA)传递的dataA, * 本线程exchanger.exchange的返回值时另一线程exchanger.exchange(dataB)传递的参数dataB */

currentBuffer = exchanger.exchange(currentBuffer);

}

}

} catch (InterruptedException ex) { ...handle ...}

}

}

void start()

{

new Thread(new FillingLoop()).start();

new Thread(new EmptyingLoop()).start();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值