Java Synchronized 同步锁的基本用法

synchronized的两种用法

  1. 对象锁
    包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定的锁对象)
  2. 类锁
    指synchronized修饰静态的方法或指定锁为class
  • 在全局同步一个方法。
    1. 多个线程共享一个runnable时,可以使用对象锁。
    2. 多个线程间使用各自的runnable时,可以使用类锁。实现全局同步

synchronized工作流程

  1. 线程加锁时,将工作内存中的共享变量的值清空,从而使用共享变量时需要从主内存中重新读取最新的值。
  2. 线程解锁前,把共享变量的最新值刷新到主内存

synchronized对象锁之同步代码块锁

public class SynchronizedObjectCodeBlock implements Runnable {
    static SynchronizedObjectCodeBlock instance = new SynchronizedObjectCodeBlock();

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        //和thread.join()方法的原理类似
        while (t1.isAlive() || t2.isAlive()) {
        }
        System.out.println("finish");
    }

    @Override
    public void run() {
        //如果有多个synchronized对象,则不能使用this了,使用自己定义的Object作为锁对象
        synchronized (this) {
            System.out.println("线程=" + Thread.currentThread().getName() + ",开始");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程=" + Thread.currentThread().getName() + ",结束");
        }
    }
}

线程=Thread-0,开始
线程=Thread-0,结束
线程=Thread-1,开始
线程=Thread-1,结束
finish
  • 如果有多个synchronized对象,则不能使用this了,使用自己定义的Object作为锁对象
public class SynchronizedObjectCodeBlock implements Runnable {
    static SynchronizedObjectCodeBlock instance = new SynchronizedObjectCodeBlock();
    Object lock1 = new Object();
    Object lock2 = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        //和thread.join()方法的原理类似
        while (t1.isAlive() || t2.isAlive()) {
        }
        System.out.println("finish");
    }

    @Override
    public void run() {
        //如果有多个synchronized对象,则不能使用this了,使用自己定义的Object作为锁对象
        synchronized (lock1) {
            System.out.println("线程=" + Thread.currentThread().getName() + ",锁lock1,开始");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程=" + Thread.currentThread().getName() + ",锁lock1,结束");
        }
        synchronized (lock2) {
            System.out.println("线程=" + Thread.currentThread().getName() + ",锁lock2,开始");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程=" + Thread.currentThread().getName() + ",锁lock2,结束");
        }
    }
}

线程=Thread-0,锁lock1,开始
线程=Thread-0,锁lock1,结束
线程=Thread-1,锁lock1,开始
线程=Thread-0,锁lock2,开始
线程=Thread-1,锁lock1,结束
线程=Thread-0,锁lock2,结束
线程=Thread-1,锁lock2,开始
线程=Thread-1,锁lock2,结束
finish

synchronized对象锁之方法锁

  • synchronized修饰普通方法,锁对象默认为this
public class SynchronizedObjectMethod implements Runnable {
    static SynchronizedObjectCodeBlock instance = new SynchronizedObjectCodeBlock();

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        //和thread.join()方法的原理类似
        while (t1.isAlive() || t2.isAlive()) {
        }
        System.out.println("finish");
    }

    @Override
    public void run() {
        method();
    }

    private synchronized void method() {
        System.out.println("线程=" + Thread.currentThread().getName() + ",开始");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程=" + Thread.currentThread().getName() + ",结束");
    }
}

线程=Thread-0,锁lock1,开始
线程=Thread-0,锁lock1,结束
线程=Thread-1,锁lock1,开始
线程=Thread-1,锁lock1,结束
finish

synchronized类锁之static方法锁

  • 如果不加static,是一个普通方法。可以并行
public class SynchronizedClassStatic implements Runnable{

    static SynchronizedClassStatic instance1 = new SynchronizedClassStatic();
    static SynchronizedClassStatic instance2 = new SynchronizedClassStatic();

    public static void main(String[] args) {
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        //和thread.join()方法的原理类似
        while (t1.isAlive() || t2.isAlive()) {
        }
        System.out.println("finish");
    }

    @Override
    public void run() {
        method();
    }

    private synchronized void method() {
        System.out.println("线程=" + Thread.currentThread().getName() + ",开始");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程=" + Thread.currentThread().getName() + ",结束");
    }
}

线程=Thread-0,开始
线程=Thread-1,开始
线程=Thread-1,结束
线程=Thread-0,结束
finish
  • 改为static方法后,一次只能有一个执行
    等同于当前类的class锁
public class SynchronizedClassStatic implements Runnable {

    static SynchronizedClassStatic instance1 = new SynchronizedClassStatic();
    static SynchronizedClassStatic instance2 = new SynchronizedClassStatic();

    public static void main(String[] args) {
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        //和thread.join()方法的原理类似
        while (t1.isAlive() || t2.isAlive()) {
        }
        System.out.println("finish");
    }

    @Override
    public void run() {
        method();
    }

    private synchronized static void method() {
        System.out.println("线程=" + Thread.currentThread().getName() + ",开始");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程=" + Thread.currentThread().getName() + ",结束");
    }
}

线程=Thread-0,开始
线程=Thread-0,结束
线程=Thread-1,开始
线程=Thread-1,结束
finish

synchronized类锁之class锁

public class SynchronizedClassClass implements Runnable {
    static SynchronizedClassClass instance1 = new SynchronizedClassClass();
    static SynchronizedClassClass instance2 = new SynchronizedClassClass();

    public static void main(String[] args) {
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        //和thread.join()方法的原理类似
        while (t1.isAlive() || t2.isAlive()) {
        }
        System.out.println("finish");
    }

    @Override
    public void run() {
        method();
    }

    private void method() {
        synchronized (SynchronizedClassClass.class) {
            System.out.println("线程=" + Thread.currentThread().getName() + ",开始");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程=" + Thread.currentThread().getName() + ",结束");
        }
    }
}

线程=Thread-0,开始
线程=Thread-0,结束
线程=Thread-1,开始
线程=Thread-1,结束
finish

synchronized与Lock.lock()/Lock.unlock()的区别

  • 1.synchronized无法判断锁状态,不知当前线程是否锁住。Lock可以判断是否获取到锁
  • 2.synchronized不可中断,如果线程迟迟拿不到一把锁,这把锁被其他线程占用,会出现该线程一直等待。
  • 3.synchronized为非公平锁,任何新线程过来与原先排队等待的线程都有相同的机会获得锁,Lock可以自己写控制
  • 4.关键字实现获取锁与释放锁,中间不可控
  • 5.synchronized是托管于JVM上执行的。lock是java类在java代码上自己写的控制代码,所以synchronized相对于lock是比较低效的
  • 6.由于性能问题,synchronized适合少量代码的同步问题,lock可用于大量代码的同步。
  • 7.synchronized悲观锁,同一时刻只有一个线程可以访问,其他线程阻塞。
    lock乐观锁,访问失败重试。

lock的作用是保护多线程访问的共享资源,而wait的作用是用于多线程之间的线程通信,作用不一样

class Outputter1 {  
    private Lock lock = new ReentrantLock();// 锁对象  
    public void output(String name) {  
        // TODO 线程输出方法  
        lock.lock();// 得到锁  
        try {  
            for(int i = 0; i < name.length(); i++) {  
                System.out.print(name.charAt(i));  
            }  
        } finally {  
            lock.unlock();// 释放锁  
        }  
    }  
}  

这样就实现了和sychronized一样的同步效果,需要注意的是,用sychronized修饰的方法或者语句块在代码执行完之后锁自动释放,而用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内。

Object.wait、Object.notify

  • wait进入锁对象的等待队列
  • notify,其他线程通过调用notify释放锁,则处于wait状态的线程,可以去竞争该锁。

sleep、wait

  • sleep阻塞线程的执行,但是不改变锁的状态
  • wait是需要锁来控制的。

参考资料

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值