【JAVA】Java并发编程二

一、同步

1、ReentrantLock object(可重用锁)

myLock.lock(); // a ReentrantLock object
try
{
 critical section
}
finally
{
 myLock.unlock(); // make sure the lock is unlocked even if an exception is thrown
}

在进入临界区之前上锁,然后再finally里释放锁。

(1)这个锁可以被同一个线程重复获取,例如,假设进入临界区之前对一个锁对象上了锁,在临界区中又有一个方法对同一个锁对象上了锁,这是可以被允许的,所以叫可重用锁。

(2)注意不要因为一个异常而跳出临界区,因为即使这时finally释放了锁,共享变量还可能是损坏状态,因为临界区里的代码只执行了一半。

(3)一些重要的API

java.util.concurrent.locks.Lock 5
void lock()
acquires this lock; blocks if the lock is currently owned by another thread.
void unlock()
releases this lock.
java.util.concurrent.locks.ReentrantLock 5
ReentrantLock()
constructs a reentrant lock that can be used to protect a critical section.
ReentrantLock(boolean fair)
constructs a lock with the given fairness policy. A fair lock favors the thread that has been waiting for the longest time. However, this fairness guarantee can be a significant drag on performance. Therefore, by default, locks are not required to be fair.

2、条件变量

这个跟操作系统中讲的条件变量一摸一样,记一下API就好

 java.util.concurrent.locks.Lock 5

Condition newCondition()
returns a condition object associated with this lock.
java.util.concurrent.locks.Condition 5
void await()
puts this thread on the wait set for this condition.
void signalAll()
unblocks all threads in the wait set for this condition.
void signal()
unblocks one randomly selected thread in the wait set for this condition.

3、synchronized关键字

首先,每个java对象都有一个内部锁,如果一个方法生命时前面有synchronized关键字,那么调用该方法就需要获得内部对象锁,也就是说,下面这个synchronized代码,

public synchronized void method()
{
 method body
}

等价于这个

public void method()
{
 this.intrinsicLock.lock();
 try
 {
 method body
 }
 finally
 {
 this.intrinsicLock.unlock();
 }
}

其次,还有wait、notifyall和notify方法可以配合使用,但是这相当于只有一个条件变量,有时可能实现不了想要做的事情。

也可以将一个静态方法声明为synchronized,这样这个方法就需要获得这个类对象的内部锁,例如bank类有一个静态的synchronized方法,再调用这个方法的时候,需要获得bank.class对象的内部锁。

这时就会产生一个问题,该如何选择同步方法呢

1)最好既不使用Lock/Condition也不使用Synchronized关键字,在许多情况下可以使用java.util.concurrent提供的机制来完成

2)如果不行,那就尽量使用Synchronized关键字,因为这样代码编写起来会简单。

3)如果还是不行,那就用Lock/Condition把。

4、synchronized块

看下面这个例子,在一个方法中用了synchronized块

public void transfer(Vector<Double> accounts, int from, int to, int amount) {
    synchronized (accounts) {
        accounts.set(from, accounts.get(from) - amount);
        accounts.set(to, accounts.get(to) + amount);
    }
    System.out.println(. . .);
}

注意synchronized块只是调用了对象的内部锁,换句话说,我们在这个方法里请求了锁,但没法确保别的方法是否请求了锁,例如,set方法可能不是synchronized的,尽管我们获得了锁,但是别人在修改数据时可能并不需要获得这个锁。我们必须基于 这个类会对自己所有的更改方法使用内部锁 这一事实,才能保证这个例子可行。

5、volatile字段

对一个实例字段声明volatile,编译器就会插入适当的代码,以确保如果一个线程对这个实例字段做了修改,这个修改对读取这个变量的其他线程都可见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值