一、锁
使用锁是Java中解决线程安全性问题的主要方法
Java中锁最主要有以下两种
1.内存锁:synchronized
2.可重入锁:lock(ReentrantLock)
二、公平锁和非公平锁
公平锁一定要执行的步骤:上一个线程释放锁之后,执行唤醒操作如何最前面的线程从阻塞状态又切换成运行状态(和非公平锁最主要的区别就是要排队执行)
非公平锁的唤醒机制是随机的,所以性能比较高,一般默认是非公平锁
二、synchronized是如何实现的
JVM层面synchronized是依靠监视器Monitor实现的:
从操作系统层面来看,是基于操作系统的互斥锁(mvtex)来实现
三、synchronized的特性
1.互斥性(排它性)
synchronized 会起到互斥效果, 某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也
执⾏到同⼀个对象 synchronized 就会阻塞等待.
进⼊ synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁
2.刷新内存(解决内存可见性问题)
synchronized 的⼯作过程:
- 获得互斥锁
- 从主内存拷⻉变量的最新副本到⼯作的内存
-
- 执⾏代码
- 将更改后的共享变量的值刷新到主内存
- 释放互斥锁
所以 synchronized 也能保证内存可⻅性
3.可重入
synchronized 同步块对同⼀条线程来说是可重⼊的,不会出现⾃⼰把⾃⼰锁死的问题。
四、lock锁
步骤:1.创建lock
2.加锁lock.lock()
3.释放锁lock.unlock()使用try{}finally{}
lock可以指定锁的类型(公平锁和非公平锁)默认情况下是非公平锁
五、lock的注意事项
1.unlock操作一定要放在finally里面,因为如果不放在里面可能会导致加了锁,业务异常之后跳过unlock方法从而导致了锁资源永久被占用的问题。
2.lock()一定要放在rty之前或者rty的首行
如果不这么放会导致的问题有两种
1.加了锁但是没有释放锁
2.释放锁的错误信息会覆盖业务的报错,这样就会增加了修改bug的难度。
六、synchronized和lock(Reentrantlock)的区别
- lock更灵活,有更多的方法比如rtylock()有返回值
- 锁类型不同,lock默认是非公平锁,但是也可以指定为公平锁,synchronized只能是非公平锁
- 调用的lock和syd线程状态不同,lock->ANTITNG(无限等待状态),synchronized->BLOCKED.ANTITNG(有等待时间的等待状态)
- synchronized是JVM层面提供的锁,它是自定义进行加锁和释放锁的,开发者无感,而lock需要开发者自己手动释放锁操作。
- synchronized可以修饰(静态方法和普通方法)和代码块,lock只能修饰代码块
synchronized VS Lock
lock 粒度可以更⼩
Lock 需要⼿动操作锁,⽽ Synchronized 是 JVM ⾃动操作的
Lock 只能修饰代码块,⽽ Synchronized 可以修饰⽅法、静态⽅法、代码块
Lock 可以创建公平锁,⽽ Synchronized 是⾮公平锁
七、内置锁:synchronized基本用法(代码示例)
1.修饰静态方法
2.修饰普通方法
3.修饰普通代码块
1.修饰静态方法
修饰++方法–方法
package Thread;
/**
* synchronized修饰静态方法
*/
public class ThreadSynchronized1 {
private static int number = 0 ;
static class Counter{
private static int MAX_COUNT=1000000;
//++方法
public synchronized static void incr(){
for(int i=0;i<MAX_COUNT;i++){
number++;
}
}
//--方法
public synchronized static void derc(){
for(int i = 0; i<MAX_COUNT;i++){
number--;
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
Counter.incr();
});
t1.start();
Thread t2 = new Thread(()->{
Counter.derc();
});
t2.start();
//等待线程执行完
t1.join();
t2.join();
System.out.println("最终的结果"+number);
}
}
2.修饰普通方法
package Thread;
/**
* synchronized 修饰普通方法
*/
public class ThreadSynchronized2 {
private static int number = 0 ;
static class Counter{
//循环次数
private static int MAX_COUNT = 1000000;
//++方法
public synchronized void incr(){
for(int i = 0;i<MAX_COUNT;i++){
number++;
}
}
public synchronized void drcr(){
for(int i = 0;i<MAX_COUNT;i++){
number--;
}
}
//--方法
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(()->{
counter.drcr();
});
t1.start();
Thread t2 = new Thread(()->{
counter.incr();
});
t2.start();
//等待线程执行完
t1.join();
t2.join();
System.out.println("最终结果"+number);
}
}
}
3.修饰普通代码块
修饰的必须是同一个对象,不然锁会失效
静态方法中不可使用this对象
stbchronized(对象){}
//(this非静态方法)
//可以自定义锁对象
package Thread;
/**
* synchronized 修饰代码
*/
public class ThreadSynchronized3 {
private static int number = 0;
static class Counter {
// 循环次数
private static int MAX_COUNT = 1000000;
// 自定义锁对象(属性名可以自定义)
private Object mylock = new Object();
// ++ 方法
public void incr() {
for (int i = 0; i < MAX_COUNT; i++) {
synchronized (mylock) {
number++;
}
}
}
public static void test() {
synchronized (Counter.class) {
}
}
// -- 方法
public void decr() {
for (int i = 0; i < MAX_COUNT; i++) {
synchronized (mylock) {
number--;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
counter.incr();
});
t1.start();
Thread t2 = new Thread(() -> {
counter.decr();
});
t2.start();
// 等待线程执行完成
t1.join();
t2.join();
System.out.println("最终的结果:" + number);
}
}
八、lock代码示例
1.创建lock
2.加锁lock.lock()
3.释放锁lock.unlock()使用try{}finally{}
package Thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 手动锁(可重入锁)的基本使用
*/
public class ThreadLock1 {
public static void main(String[] args) {
//创建锁
Lock lock = new ReentrantLock();
//加锁操作
lock.lock();
try{
System.out.println("你好,ReentrantLock!");
}finally {
lock.unlock();
}
}
}
package Thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadLock2 {
private static int number = 0 ;
static class Counter{
private static Lock lock = new ReentrantLock();//默认非公平锁,设置为true时为公平锁
private static int MAX_COUNT=1000000;
//++方法
public static void incr(){
for(int i=0;i<MAX_COUNT;i++){
lock.lock();//加锁操作
try{
number++;
}finally {
lock.unlock();//释放锁
}
}
}
//--方法
public static void derc(){
for(int i = 0; i<MAX_COUNT;i++){
lock.lock();
try{
number--;
}finally{
lock.unlock();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
Counter.incr();
});
t1.start();
Thread t2 = new Thread(()->{
Counter.derc();
});
t2.start();
t1.join();
t2.join();
System.out.println(number);
}
}