提示:以下是本篇文章正文内容,Java系列学习将会持续更新
一、synchronzied
什么是锁?
为了解决线程不安全的问题,JVM设置了一种机制。当一个线程对共享数据进行操作时,其他线程不能参加,直到等A线程操作完毕才能依次进行,也就是同步机制。
synchronized的作用:实现线程同步,让多个线程排序依次获取共享资源,防止共享数据出错。
互斥锁:即能达到互斥访问目的的锁,也就是说当一个共享数据被当前正在访问的线程加上互斥锁后,在同一个时刻,其他线程只能处于等待的状态,直到当前线程处理完毕释放该锁。
互斥条件:多个线程都有加锁操作 && 锁的是同一个对象
syn语法
修饰方法
// 静态方法,锁定的是类
synchronized static void fun1() { }
// 非静态方法,锁定的是方法的调用者
synchronized void fun2() { }
修饰代码块,锁定的是传入的对象
Object o1 = new Object();
void fun3() {
synchronized (o1) { }
}
void fun4() {
synchronized (Test.class) { }
}
JVM对所有的类都实现了“锁”的功能。
如何正确加锁?
七个场景,有对有错
syn的工作原理
syn加锁的作用
1.原子性(90%):将需要保证原子性的操作互斥起来
加锁粒度越细,并发性越高。但并不一定粒度越细越好。
2.可见性(5%)
3.重排序(5%)
二、Lock
Lock锁的使用
Lock是JDK1.5出现的一种锁的实现方式,是一个接口。弥补了syn使用中的不足。
实现类:ReentrantLock, ReadLock, WriteLock
java.util.concurrent.locks.Lock | |
---|---|
void lock(); | 获取锁。效果等同于syn |
void lockInterruptibly(); | 加锁并且线程允许被中断。 |
boolean tryLock(); | 尝试去加锁,失败返回false。 |
boolean tryLock(long time,TimeUnit unit); | 在等待时间内加锁。等待过程允许被中断 |
void unlock(); | 释放锁。 |
ReentrantLock的使用:
/**
* ReentrantLock的使用
*/
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo1 {
// 定义一个被操作的数
static int r = 0;
// 定义操作的数
static final int COUNT = 1000_0000;
static class Add extends Thread {
Lock o;
Add(Lock o) {
this.o = o;
}
@Override
public void run() {
o.lock(); // 获取锁
try {
for (int i = 0; i < COUNT; i++) {
r++;
}
}finally { // 将解锁操作放在finally中,确保任何情况都可以进行
o.unlock(); // 释放锁
}
}
}
static class Sub extends Thread {
Lock o;
Sub(Lock o) {
this.o = o;
}
@Override
public void run() {
o.lock(); // 加锁
try {
for (int i = 0; i < COUNT; i++) {
r--;
}
} finally {
o.unlock(); // 解锁
}
}
}
public static void main(String[] args) throws InterruptedException {
// 定义一个锁对象
Lock o = new ReentrantLock();
// 将锁传入线程中
Thread add = new Add(o);
add.start();
Thread sub = new Sub(o);
sub.start();
// 等待结束
add.join();
sub.join();
// 加锁后线程安全
System.out.println(r);
// 加锁使得两个线程互斥执行
}
}
Lock比synchronized更灵活:
Lock的多种应用场景
死锁
所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。
造成死锁的原因:
·当前线程拥有其他线程需要的资源
·当前线程等待其他线程已拥有的资源
·都不放弃自己拥有的资源
避免死锁的三种技术:
·加锁顺序(线程按照一定的顺序加锁)
·加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
·死锁检测(tryLock())
三、syn锁 vs JUC锁
synchronzied | Juc包下的锁 | |
---|---|---|
来源 | Java内置的关键字 | 继承了Lock接口,有很多实现类 |
代码语法 | 自动释放锁 | 需要手动释放锁 |
灵活程度 | 比较单一 | 可以在一个方法中加锁,到另一个方法中解锁 |
锁的类型 | syn是独占锁、可重入锁、非公平锁 | 锁的类型更多:公平锁/非公平锁、读写锁/独占锁、可重入锁/不可重入锁 |
加锁策略 | 只能请求锁 | 加锁策略灵活:请求锁、可中断的锁、尝试锁、请求失败 |
线程间通信 | Object类中的wait()和notify() | Condition对象的await()和signal() |
总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是Java多线程的学习,认识了什么是锁,关键字synchronized和Lock这两种锁的用法。之后的学习内容将持续更新!!!