Java线程锁Synchronized

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_33411202/article/details/102696650
什么是线程锁?

在并发编程中,经常遇到多个线程访问同一个 共享资源 ,这时候作为开发者必须考虑如何维护数据一致性,在java中synchronized关键字被常用于维护数据一致性。synchronized机制是给共享资源上锁,只有拿到锁的线程才可以访问共享资源,这样就可以强制使得对共享资源的访问都是顺序的。

引入多线程后,为解决线程安全问题而引入锁的概念,java中常用的锁有synchronized和lock两种。

java中的锁

一般在java中所说的锁就是指的内置锁,每个java对象都可以作为一个实现同步的锁,虽然说在java中一切皆对象, 但是锁必须是引用类型的,基本数据类型则不可以 。每一个引用类型的对象都可以隐式的扮演一个用于同步的锁的角色,执行线程进入synchronized块之前会自动获得锁,无论是通过正常语句退出还是执行过程中抛出了异常,线程都会在放弃对synchronized块的控制时自动释放锁。 获得锁的唯一途径就是进入这个内部锁保护的同步块或方法 。

通过synchronized的关键字来实现线程同步锁

synchronized 锁住的是对象

Synchronized 三种应用方式:

1.作用于实例方法(普通方法),当前实例加锁,进入同步代码前要获得当前实例的锁;
例如:

public class SyncTest implements Runnable{
//共享资源变量
static int count = 0;

    @Override
    public synchronized void run() {
        increaseCount();
    }

    private synchronized  void increaseCount() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + count++);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncTest syncTest1 = new SyncTest();
//        SyncTest syncTest2 = new SyncTest();
        Thread thread1 = new Thread(syncTest1, "thread1");
        Thread thread2 = new Thread(syncTest1, "thread2");
        thread1.start();
        thread2.start();
    }
    
    /**
     * 执行结果
     * thread1:0
     * thread1:1
     * thread1:2
     * thread1:3
     * thread1:4
     * thread2:5
     * thread2:6
     * thread2:7
     * thread2:8
     * thread2:9
     */
}

上面是创建1个对象和两个线程,可以看到Thread1和Thread2 按顺序执行
当创建两个不同的对象时,两个线程同步执行,所以说锁住的是对象。如下:

public class SyncTest implements Runnable{
//共享资源变量
static int count = 0;

    @Override
    public synchronized void run() {
        increaseCount();
    }

    private synchronized  void increaseCount() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + count++);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncTest syncTest1 = new SyncTest();
        SyncTest syncTest2 = new SyncTest();
        Thread thread1 = new Thread(syncTest1, "thread1");
        Thread thread2 = new Thread(syncTest2, "thread2");
        thread1.start();
        thread2.start();
    }

    /**
     * 执行结果
     thread2:1
     thread1:0
     thread1:2
     thread2:3
     thread2:4
     thread1:4
     thread1:5
     thread2:5
     thread2:6
     thread1:7
     */
}

2.作用于静态方法,当前类加锁,进去同步代码前要获得当前类对象的锁;

public class SyncTest implements Runnable {
    //共享资源变量
    static int count = 0;

    @Override
    public synchronized void run() {
        increaseCount();
    }

    private sys static void increaseCount() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + count++);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncTest syncTest1 = new SyncTest();
        SyncTest syncTest2 = new SyncTest();
        Thread thread1 = new Thread(syncTest1, "thread1");
        Thread thread2 = new Thread(syncTest2, "thread2");
        thread1.start();
        thread2.start();
    }

    /**
     * 执行结果
     thread1:0
     thread1:1
     thread1:2
     thread1:3
     thread1:4
     thread2:5
     thread2:6
     thread2:7
     thread2:8
     thread2:9
     */
}

synchronized 作用于静态方法时,相当于给该类加锁,如上创建两个对象分开两个线程依旧按顺序执行。

3.作用于代码块,这需要指定加锁的对象,对所给的指定对象加锁,进入同步代码前要获得指定对象的锁。

public class SyncTest implements Runnable {
    //共享资源变量
    static int count = 0;
    private byte[] mBytes = new byte[0];

    @Override
    public synchronized void run() {
        increaseCount();
    }

    private void increaseCount() {
        //假设省略了其他操作的代码。
        //……………………
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ":" + count++);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncTest syncTest1 = new SyncTest();
        SyncTest syncTest2 = new SyncTest();
        Thread thread1 = new Thread(syncTest1, "thread1");
        Thread thread2 = new Thread(syncTest1, "thread2");
        thread1.start();
        thread2.start();
    }

    /**
     * 执行结果
     thread1:0
     thread1:1
     thread1:2
     thread1:3
     thread1:4
     thread2:5
     thread2:6
     thread2:7
     thread2:8
     thread2:9
     */

当只需要部分代码同步时,synchronized 作用于代码块,传入参数为对象,效果和作用于普通方法一致,锁住的是对象。

参考:
https://www.cnblogs.com/JackpotHan/category/1305465.html


https://www.cnblogs.com/wangyayun/p/6593446.html

Synchronized三种用法

猜你喜欢

转载自blog.csdn.net/qq_33411202/article/details/102696650