解决多线程中的安全问题锁(synchronized&lock)

一、锁

使用锁是Java中解决线程安全性问题的主要方法
Java中锁最主要有以下两种
1.内存锁:synchronized
2.可重入锁:lock(ReentrantLock)

二、公平锁和非公平锁
公平锁一定要执行的步骤:上一个线程释放锁之后,执行唤醒操作如何最前面的线程从阻塞状态又切换成运行状态(和非公平锁最主要的区别就是要排队执行)
非公平锁的唤醒机制是随机的,所以性能比较高,一般默认是非公平锁

二、synchronized是如何实现的

JVM层面synchronized是依靠监视器Monitor实现的:
从操作系统层面来看,是基于操作系统的互斥锁(mvtex)来实现

三、synchronized的特性

1.互斥性(排它性)
synchronized 会起到互斥效果, 某个线程执⾏到某个对象的 synchronized 中时, 其他线程如果也
执⾏到同⼀个对象 synchronized 就会阻塞等待.
进⼊ synchronized 修饰的代码块, 相当于 加锁
退出 synchronized 修饰的代码块, 相当于 解锁
2.刷新内存(解决内存可见性问题)
synchronized 的⼯作过程:

  1. 获得互斥锁
  2. 从主内存拷⻉变量的最新副本到⼯作的内存
    1. 执⾏代码
  3. 将更改后的共享变量的值刷新到主内存
  4. 释放互斥锁
    所以 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)的区别

  1. lock更灵活,有更多的方法比如rtylock()有返回值
  2. 锁类型不同,lock默认是非公平锁,但是也可以指定为公平锁,synchronized只能是非公平锁
  3. 调用的lock和syd线程状态不同,lock->ANTITNG(无限等待状态),synchronized->BLOCKED.ANTITNG(有等待时间的等待状态)
  4. synchronized是JVM层面提供的锁,它是自定义进行加锁和释放锁的,开发者无感,而lock需要开发者自己手动释放锁操作。
  5. 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);
    }
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值