1.synchronized
synchronized关键字是一个悲观锁,可以用于变量,方法及类。
很多人会将synchronized和volatile做比较,个人理解volatile其实就是将一个变量公开话,一个线程修改,任何线程可同步见到。
volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取。
2.ReentrantLock
ReentrantLock 与 synchronized 很相似,也是一种互斥锁(lock),只是ReentrantLock 相对 synchronized 而言还是增加了一些高级功能.
等待可中断:lock.lockInterruptibly();//获取响应中断锁
public class lockReentrantLock {
private Lock lock = new ReentrantLock();
public static void main(String[] args) {
final lockReentrantLock buff = new lockReentrantLock();
final Thread writer = new Thread(new Runnable() {
public void run() {
try {
buff.write();
} catch (InterruptedException e) {
System.out.println("写中断异常");
}
System.out.println("写结束");
}
});
final Thread reader = new Thread(new Runnable() {
public void run() {
try {
buff.reader();
} catch (InterruptedException e) {
System.out.println("我不想读了");
}
System.out.println("读结束"); }
});
writer.start();
reader.start();
// 中断读操作
new Thread(new Runnable() {
public void run() {
long start = System.currentTimeMillis();
for (;;) {
if (System.currentTimeMillis()
- start > 5000) {
System.out.println("不等了,尝试中断");
reader.interrupt(); //此处中断读操作
break; } } } }).start();
}
public void reader() throws InterruptedException{
lock.lockInterruptibly();
System.out.println("开始读数据");
lock.unlock(); }
public void write() throws InterruptedException{
lock.lock();
long starttime=System.currentTimeMillis() ;
System.out.println("开始写数据");
for(;;)
{
if(System.currentTimeMillis() -starttime>10000)
{
System.out.println("终于写数据结束了");
break; }
}
lock.unlock();
}
}
输出结果
可实现公平锁:(公平锁)多线程获取锁的顺序是按照线程加锁的顺序来分配的。(非公平锁)都是随机,可能造成某些线程一直无法运行。
公平锁: Lock lock = new ReentrantLock(true); 非公平锁: Lock lock = new ReentrantLock(false);
ReentrantReadWriteLock类
public static void main(String[] args){
final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
Thread reader=new Thread(new Runnable() {
public void run() {
try {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " 获得读锁,当前时间" + System.currentTimeMillis());
Thread.sleep(5000);
} finally {
lock.readLock().unlock();
}
}catch ( Exception e)
{ } }
});
reader.setName("readerOne");
reader.start();
Thread reader1=new Thread(new Runnable() {
public void run() {
try {
try {
lock.readLock().lock();
System.out.println(Thread.currentThread().getName() + " 获得读锁,当前时间" + System.currentTimeMillis());
} finally {
lock.readLock().unlock();
}
}catch ( Exception e)
{ }}
});
reader1.setName("readerTwo");
reader1.start();
}
输出
将readLock改成writeLock 可以看出读和读是共享得 读写互斥 写写互斥。
锁可以绑定多个条件:ReentrantLock 对象可以同时绑定多个 Condition 对象(名曰:条件变量或条件队列),而在 synchronized 中,锁对象的 wait()和 notify()或 notifyAll()方法可以实现一个隐含条件,但如果要和多于一个的条件关联的时候,就不得不额外地添加一个锁,而 ReentrantLock 则无需这么做,只需要多次调用 newCondition()方法即可。而且我们还可以通过绑定 Condition 对象来判断当前线程通知的是哪些线程(即与 Condition 对象绑定在一起的其他线程)Condition是Java提供了来实现等待/通知的类,Condition类还提供比wait/notify更丰富的功能,Condition对象是由lock对象所创建的。但是同一个锁可以创建多个Condition的对象,即创建多个对象监视器。这样的好处就是可以指定唤醒线程。notify唤醒的线程是随机唤醒一个
public static void main(String[] args){
final Lock lock = new ReentrantLock();
final Condition condition=lock.newCondition();
Thread reader=new Thread(new Runnable() {
public void run() {
try {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "await 开始执行时间" + System.currentTimeMillis());
condition.await();
System.out.println(Thread.currentThread().getName() + "await 结束时间aaa" + System.currentTimeMillis());
} finally {
lock.unlock();
}
}catch ( Exception e)
{ } }
});
reader.setName("A");
reader.start();
Thread b=new Thread(new Runnable() {
public void run() {
try {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "await 开始执行时间" + System.currentTimeMillis());
// condition.awaitUntil();
System.out.println(Thread.currentThread().getName() + "await 结束时间bbb " + System.currentTimeMillis());
} finally {
lock.unlock();
}
}catch ( Exception e)
{ } }
});
b.setName("B");
b.start();
Thread reader2=new Thread(new Runnable() {
public void run() {
try {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + "signal 开始执行时间" + System.currentTimeMillis());
condition.signalAll(); //如果是signal的话 只能唤醒一个线程
System.out.println(Thread.currentThread().getName() + "signal 结束时间" + System.currentTimeMillis());
} finally {
lock.unlock();
}
}catch ( Exception e)
{ } }
});
reader2.setName("C");
reader2.start();
输出:
Aawait 开始执行时间1603283537973
Bawait 开始执行时间1603283537974
Csignal 开始执行时间1603283537977
Csignal 结束时间1603283537977
Aawait 结束时间aaa1603283537977
Bawait 结束时间bbb 1603283537977
参考文章:
https://www.cnblogs.com/qifengshi/p/6354890.html