Synchronized是并发中使用最频繁的关键字了,它可以使用在方法、代码块上,表示对该段代码加锁,而必须要持有锁才能执行这段代码。Synchronized具有互斥性。
说起来蛮简单,而实际中编程 ,最难得地方有两点
1、确定并发间隙
2、确定锁的对象
做好这两点才能处理好锁的粒度,是并发的性能更好。
eg1、Synchronized加在静态方法上,不同的线程调用这两个方法互斥。此时synchronize锁的是该类
public class SynchronizeDemo1 {
public synchronized static void fool1() throws Exception{
System.out.println("fool1...开始");
Thread.sleep(10000L);
System.out.println("fool1...结束");
}
public synchronized static void fool2() throws Exception{
System.out.println("fool2...开始");
Thread.sleep(5000L);
System.out.println("fool2...结束");
}
public static void main(String args[]){
new Thread(new Runnable() {
@Override
public void run() {
try {
SynchronizeDemo1.fool1();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
SynchronizeDemo1.fool2();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();;
}
}
eg2、Synchronized加在成员方法上,不同的线程调用同一对象的成员方法互斥
package com.base.thread.synchronize;
public class SynchronizeDemo2 {
public synchronized void fool1() throws Exception{
System.out.println("fool1...开始");
Thread.sleep(10000L);
System.out.println("fool1...结束");
}
public synchronized void fool2() throws Exception{
System.out.println("fool2...开始");
Thread.sleep(5000L);
System.out.println("fool2...结束");
}
public static void main(String args[]){
final SynchronizeDemo2 synchronizeDemo2 = new SynchronizeDemo2();
new Thread(new Runnable() {
@Override
public void run() {
try {
// new SynchronizeDemo2().fool1();
synchronizeDemo2.fool1();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
// new SynchronizeDemo2().fool2();
synchronizeDemo2.fool1();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();;
}
}
eg3、foo3和foo4不互斥,foo1和foo4互斥,foo2和foo3互斥
public class SynchronizeDemo3 {
public static synchronized void fool1() throws Exception{
System.out.println("fool1...开始");
Thread.sleep(10000L);
System.out.println("fool1...结束");
}
public synchronized void fool2() throws Exception{
System.out.println("fool2...开始");
Thread.sleep(5000L);
System.out.println("fool2...结束");
}
public void fool3() throws Exception{
synchronized(this){
System.out.println("fool3...开始");
Thread.sleep(5000L);
System.out.println("fool3...结束");
}
}
public void fool4() throws Exception{
synchronized(SynchronizeDemo3.class){
System.out.println("fool4...开始");
Thread.sleep(5000L);
System.out.println("fool4...结束");
}
}
public static void main(String args[]){
new Thread(new Runnable() {
@Override
public void run() {
try {
new SynchronizeDemo3().fool3();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
new SynchronizeDemo3().fool4();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();;
}
}
LOCK
Lock比synchronized更加面向对象,锁本身就是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。
ReentrantLock
ReentrantLock是Lock的实现,被称作重入锁,它的功能比Synchronized强大,但是jdk1.6之后两者性能差别不大,Synchronized使用更简单清晰,所以多线程加锁还是首选Synchronized。
ReentrantLock提供了公平和非公平两种锁。通过构造方法可以实现,但是公平锁的性能远远低于非公平锁,因此非特殊情况优先非公平锁。
注意:ReenTrantLock使用之后,必须释放锁。
ReentrantLock 锁提供了如下重要的方法:
lock():获得锁,如果锁已经被占用,则等待
lockInterruptibly():获得锁,但优先响应中断
tryLock():尝试获得锁,如果成功,返回true,失败返回false。该方法不等待,立即返回
unlock():释放锁
ReentrantReadWriteLock 读写锁
分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。如果代码是只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!
public class ReadWriteLockTest{
private Integer num = 0;
private Lock lock = new ReentrantLock();
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
private ReadLock readLock = reentrantReadWriteLock.readLock();
private WriteLock writeLock = reentrantReadWriteLock.writeLock();
public int read1(){
try{
lock.lock();
Thread.sleep(10L);
}catch(Exception e){
e.printStackTrace();
}finally{
lock.unlock();
}
return num;
}
public void write1(){
try{
lock.lock();
num++;
}finally{
lock.unlock();
}
}
public int read2(){
try{
readLock.lock();
Thread.sleep(10L);
}catch(Exception e){
e.printStackTrace();
}finally{
readLock.unlock();
}
return num;
}
public void write2(){
try{
writeLock.lock();
num++;
}finally{
writeLock.unlock();
}
}
public Integer getNum() {
return num;
}
public static void main(String args[]) throws Exception{
long time1 = System.currentTimeMillis();
final ReadWriteLockTest rwt = new ReadWriteLockTest();
List<Thread> threadList = new ArrayList<>();
for(int i = 0; i < 3000; i++){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
rwt.write1();
// rwt.write2();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
rwt.read1();
// rwt.read2();
}
});
t2.start();
threadList.add(t1);
threadList.add(t2);
}
for(Thread thread : threadList){
thread.join();
}
System.out.println("num: " + rwt.getNum());
System.out.println("耗时:" + (System.currentTimeMillis() - time1));
}
}
Condition
Condition可以替代传统的线程间通信,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll()。
——为什么方法名不直接叫wait()/notify()/nofityAll()?因为Object的这几个方法是final的,不可重写!
传统线程的通信方式,Condition都可以实现。
注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。
Condition的强大之处在于它可以为多个线程间建立不同的Condition
来源:oschina
链接:https://my.oschina.net/u/2370478/blog/754268