java 多线程 临界区_java 多线程 临界区的操作

本文探讨了在多线程环境下实现线程安全的方法,包括使用synchronized关键字和显式锁来保护共享资源免受并发修改的影响。通过具体示例对比了同步方法与临界区的优劣。
摘要由CSDN通过智能技术生成

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicInteger;

/**

* Not thread-safe

* 正如注释中注明的,Pair不是线程安全的,因为它的约束条件(虽然是任意的)需要两个变量要维护成相同的值。

* 此外,如本章前面所描述的,自增加操作不是线程安全的,并且因为没哟任何方法被标记为synchronized,所以

* 不能保证一个Pair对象在多线程程序中不会被破坏。

*

* @create @author Henry @date 2016-11-30

*/

class Pair {

private int x, y;

public Pair(int x, int y) {

this.x = x;

this.y = y;

}

public Pair() {

this(0, 0);

}

public int getX() {

return x;

}

public int getY() {

return y;

}

public void incrementX() {

x++;

}

public void incrementY() {

y++;

}

@Override

public String toString() {

return "x: " + x + ", y: " + y;

}

public class PairValuesNotEqualExceptin extends RuntimeException {

public PairValuesNotEqualExceptin() {

super("Pair values not equal : " + Pair.this);

}

}

/**

* Arbitrary invariant --both variables must be equal:

*

* @create @author Henry @date 2016-11-30

*/

public void checkState() {

if (x != y)

throw new PairValuesNotEqualExceptin();

}

}

/**

* 你可以想象一下这种情况:某人交个你一个非线程安全的Pair类,而你需要在一个线程环境中使用它。通过创建

* PairManager类就可一个实现这一点,PairManager类持有一个Pair对象并控制它的一切访问。注意唯一的

* public 方法是 getPair(),它是synchronized的。对于抽象方法increment(),对于increment()的同步

* 控制将在实现的时候进行处理。

*/

/**

* Protect a Pair inside a thread-safe class:

*

* 至于PairManager类的结构,它的一些功能在积累中实现,并且其一个或多个抽象方法在派生类中定义,

* 这种结构在设计模式中成为模板方法。设计模式使你得以把变化封装在代码里;因此,发生变化的部分是

* 模板方法increment()。

* store()方法将一个Pair对象添加到了Synchronized ArrayList中,所以这个操作是线程安全的。

* 因此,该方法不必进行防护,可以防止在PairManager2的synchronized语句块的外部。

*

* @create @author Henry @date 2016-11-30

*/

abstract class PairManager {

AtomicInteger checkCounter = new AtomicInteger(0);

protected Pair p = new Pair();

private List storage = Collections.synchronizedList(new ArrayList());

/**

* Make a copy to keep the original safe

*

* @create @author Henry @date 2016-11-30

* @return

*/

public synchronized Pair getPair() {

return new Pair(p.getX(), p.getY());

}

protected void store(Pair p) {

storage.add(p);

try {

TimeUnit.MILLISECONDS.sleep(50);

} catch (InterruptedException e) {

}

}

public abstract void increment();

}

/**

* Synchronized the entire method:

*

* 在PairManager1中,整个increment()方法被同步控制。

*

* @create @author Henry @date 2016-11-30

*

*/

class PairManager1 extends PairManager {

@Override

public synchronized void increment() {

p.incrementX();

p.incrementY();

store(getPair());

}

}

/**

* Use a critical section:

*

* 在PairManager2中,increment()方法使用同步控制块进行同步。

* 注意,synchronized关键字不属于方法特性签名的组成部分,所以可以在覆盖方法的时候加上去。

*

* @create @author Henry @date 2016-11-30

*

*/

class PairManager2 extends PairManager {

@Override

public void increment() {

Pair temp;

synchronized (this) {

p.incrementX();

p.incrementY();

temp = getPair();

}

store(temp);

}

}

/**

* PairManipulator被创建用来测试两种不同类型的PairManager,其方法是在某个任务中调用increment(),

*

* @create @author Henry @date 2016-11-30

*

*/

class PairManipulator implements Runnable {

private PairManager pm;

public PairManipulator(PairManager pm) {

this.pm = pm;

}

@Override

public void run() {

while (true)

pm.increment();

}

@Override

public String toString() {

return "Pair: " + pm.getPair() + " checkCounter = " + pm.checkCounter.get();

}

}

/**

* PairChecker则在另一个任务中执行。为了跟踪可以运行测试的频度,

* PairChecker在每次成功时都递增checkCounter。

*

* @create @author Henry @date 2016-11-30

*

*/

class PairChecker implements Runnable {

private PairManager pm;

public PairChecker(PairManager pm) {

this.pm = pm;

}

@Override

public void run() {

while (true) {

pm.checkCounter.incrementAndGet();

pm.getPair().checkState();

}

}

}

/**

* Test the two different approaches;

* 在main()中创建了两个PairManipulator对象,并运行它们运行一段时间,

* 之后每个PairManipulator的结果会得到展示。

*

* @create @author Henry @date 2016-11-30

*

*/

public class CriticalSection {

static void testApproaches(PairManager pman1, PairManager pman2) {

ExecutorService exec = Executors.newCachedThreadPool();

PairManipulator pm1 = new PairManipulator(pman1), pm2 = new PairManipulator(pman2);

PairChecker pcheck1 = new PairChecker(pman1), pcheck2 = new PairChecker(pman2);

exec.execute(pm1);

exec.execute(pm2);

exec.execute(pcheck1);

exec.execute(pcheck2);

try {

TimeUnit.MILLISECONDS.sleep(1000);

} catch (InterruptedException e) {

System.out.println("Sleep interrupted");

}

System.out.println("pm1: " + pm1 + "\npm2: " + pm2);

System.exit(0);

}

/**

* 尽管每次运行的结果可能会非常不同,但一般来说,对于PairChecker的检查频率。

* PairManager1.increment()不允许有PairManager2.increment()那样多。

* 后者采用沟通不控制块进行同步,所以对象不加锁的时间更长。这也是宁愿使用同步控制块

* 而不是对整个方法进行同步控制的典型原因:使得其他线程能更多地访问

* (在安全的情况下尽可能多)。

*

* 运行结果:

* pm1: Pair: x: 17, y: 17 checkCounter = 1714855

* pm2: Pair: x: 22, y: 22 checkCounter = 12120719

* @param args

*/

public static void main(String[] args) {

PairManager pman1 = new PairManager1(), pman2 = new PairManager2();

testApproaches(pman1, pman2);

}

}

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/**

* Synchronize the entire method:

*

* @create @author Henry @date 2016-11-30

*

*/

class ExplicitPairManager1 extends PairManager {

private Lock lock = new ReentrantLock();

@Override

public synchronized void increment() {

lock.lock();

try {

p.incrementX();

p.incrementY();

store(getPair());

} finally {

lock.unlock();

}

}

}

/**

* Use a critical section

*

* @create @author Henry @date 2016-11-30

*

*/

class ExplicitPairManager2 extends PairManager {

private Lock lock = new ReentrantLock();

@Override

public void increment() {

Pair temp;

lock.lock();

try {

p.incrementX();

p.incrementY();

temp = getPair();

} finally {

lock.unlock();

}

store(temp);

}

}

/**

* 此方式在我尝试的时候,直接出现线程不安全的异常。

* 但是结果是对的。说明lock锁的是代码线程安全,而不会锁对象同步安全。

*

* 运行结果:

* Exception in thread "pool-1-thread-4" com.think.no21.no3.Pair$PairValuesNotEqualExceptin: Pair values not equal : x: 3, y: 2

* at com.think.no21.no3.Pair.checkState(CriticalSection.java:65)

* at com.think.no21.no3.PairChecker.run(CriticalSection.java:192)

* at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

* at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

* at java.lang.Thread.run(Thread.java:662)

* pm1: Pair: x: 21, y: 21 checkCounter = 255040

* pm2: Pair: x: 22, y: 22 checkCounter = 1884633

*

* @create @author Henry @date 2016-11-30

*

*/

public class ExplicitCriticalSection {

public static void main(String[] args) {

PairManager pman1 = new ExplicitPairManager1(), pman2 = new ExplicitPairManager2();

CriticalSection.testApproaches(pman1, pman2);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值