栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程:Synchronized的使用(一)——修饰方法、静态方法、代码块

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程:Synchronized的使用(一)——修饰方法、静态方法、代码块

Synchronized是什么?

Synchronized是Java的关键字,字面意思上是同步的意思,也就是说可以用它修饰普通方法、静态方法、代码块,达到同步的效果,就是我们俗称的上锁。

Synchronized作用域和作用对象? 使用Synchronized修饰普通方法

使用Synchronized修饰普通方法,作用域是整个方法,作用对象是该类的当前对象,不同对象会持有不同的锁。下面我们来看看代码:

public class SynchronizedMethodTest {

    synchronized public void printHello() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("Hello " + name);
            Thread.sleep(1000);
        }
    }

    synchronized public void printByeBye() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("Bye Bye " + name);
            Thread.sleep(1000);
        }
    }

    public static void main(String[] args) throws InterruptedException {

        SynchronizedMethodTest s1 = new SynchronizedMethodTest();

        new Thread(() -> {
            System.out.println("Thread1 is start");
            try {
                s1.printHello();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            try {
                s1.printByeBye();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread2 is end");

        }).start();
    }
}

SynchronizedMethodTest类有两个方法:printHello和prinByeBye都加了锁,主程序new了一个SynchronizedMethodTest对象,新建两个线程分别调用s1.printHello和s1.printByeBye方法。

程序执行结果如下:

Thread1 is start
Hello Thread-0
Thread2 is start
Hello Thread-0
Hello Thread-0
Hello Thread-0
Hello Thread-0
Thread1 is end
Bye Bye Thread-1
Bye Bye Thread-1
Bye Bye Thread-1
Bye Bye Thread-1
Bye Bye Thread-1
Thread2 is end

可以发现Thread2要等Thread1执行完才执行,说明Thread1在执行printHello方法时拿到的是对象锁,即使Thread2调用的是不同方法,也需要等待。

为了证明这一点,我将代码稍作修改:

public class SynchronizedMethodTest {

    synchronized public void printHello() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("Hello " + name);
            Thread.sleep(1000);
        }
    }

    synchronized public void printByeBye() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++){
            System.out.println("Bye Bye " + name);
            Thread.sleep(1000);
        }
    }

    public static void main(String[] args) throws InterruptedException {

        SynchronizedMethodTest s1 = new SynchronizedMethodTest();
        SynchronizedMethodTest s2 = new SynchronizedMethodTest();

        new Thread(() -> {
            System.out.println("Thread1 is start");
            try {
                s1.printHello();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            try {
                s2.printByeBye();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread2 is end");

        }).start();
    }
}

这次new了两个SynchronizedMethodTest对象,新建两个线程分别执行s1.printHello、s2.printByeBye方法。

执行结果如下:

Thread1 is start
Hello Thread-0
Thread2 is start
Bye Bye Thread-1
Hello Thread-0
Bye Bye Thread-1
Hello Thread-0
Bye Bye Thread-1
Hello Thread-0
Bye Bye Thread-1
Hello Thread-0
Bye Bye Thread-1
Thread1 is end
Thread2 is end

从结果可以发现,Thread1和Thread2线程同时执行,因为这两个方法拿到的是两个不同对象的锁,所以互相不影响。

使用Synchronized修饰静态方法

使用synchronized修饰静态方法,作用域是整个静态方法,作用对象是类,与类的对象无关。下面我们来看看代码:

public class SynchronizedClassTest {

    synchronized public static void printHello() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++) {
            System.out.println("Hello " + name);
            Thread.sleep(1000);
        }
    }

    synchronized public static void printByeBye() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++) {
            System.out.println("Bye Bye " + name);
            Thread.sleep(1000);
        }
    }

    synchronized public void printGo() throws InterruptedException {
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 5; i++) {
            System.out.println("GO!" + name);
            Thread.sleep(1000);
        }
    }

    public static void main(String[] args) throws InterruptedException {

        SynchronizedClassTest s = new SynchronizedClassTest();

        new Thread(() -> {
            System.out.println("Thread1 is start");
            try {
                SynchronizedClassTest.printHello();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            try {
                SynchronizedClassTest.printByeBye();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread2 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread3 is start");
            try {
                s.printGo();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Thread3 is end");

        }).start();
    }
}

这次我们有三个方法,其中printHello和printByeBye是静态方法,printGo是普通方法,新建三个线程分别调用这三个方法,结果如下:

Thread1 is start
Hello Thread-0
Thread2 is start
Thread3 is start
GO!Thread-2
Hello Thread-0
GO!Thread-2
Hello Thread-0
GO!Thread-2
Hello Thread-0
GO!Thread-2
GO!Thread-2
Hello Thread-0
Thread3 is end
Bye Bye Thread-1
Thread1 is end
Bye Bye Thread-1
Bye Bye Thread-1
Bye Bye Thread-1
Bye Bye Thread-1
Thread2 is end

从结果可以发现Thread2要等待Thread1执行完再执行,说明对静态方法锁的是类,Thread3不受Thread1和Thread2的影响,说明对象锁和类锁不是一把锁,互不影响。

使用Synchronized修饰代码块

使用synchronized修饰代码块,作用域是整个代码块里面的内容,作用对象是括号中的对象(类、对象),作用对象是类的时候,作用的是类及该类的所有对象,下面代码可以看到:

public class SynchronizedStaticBlockTest {

    private void print(){
        synchronized (SynchronizedStaticBlockTest.class){
            String name = Thread.currentThread().getName();
            for (int i = 0; i < 5; i++) {
                System.out.println("Hello " + name);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {

        SynchronizedStaticBlockTest s1 = new SynchronizedStaticBlockTest();
        SynchronizedStaticBlockTest s2 = new SynchronizedStaticBlockTest();

        new Thread(() -> {
            System.out.println("Thread1 is start");
            s1.print();
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            s2.print();
            System.out.println("Thread2 is end");

        }).start();
    }
}

有一个方法print,其中有一个被synchronized修饰的代码块,作用对象是SynchronizedStaticBlockTest,现在新建两个SynchronizedStaticBlockTest对象,新建两个线程分别调用s1.print和s2.print,结果如下:

Thread1 is start
Hello Thread-0
Thread2 is start
Hello Thread-0
Hello Thread-0
Hello Thread-0
Hello Thread-0
Thread1 is end
Bye Bye  Thread-1
Bye Bye  Thread-1
Bye Bye  Thread-1
Bye Bye  Thread-1
Bye Bye  Thread-1
Thread2 is end

可以发现,synchronized修饰代码块,作用对象为类的时候,作用的是这个类的所有对象。

我们现在稍微修改一下代码,新增一个print2方法,内部也有一个被synchronized修饰的代码块,但这次作用对象是this,也就是当前对象,现在新建两个线程执行这个方法。

public class SynchronizedStaticBlockTest {

    public SynchronizedStaticBlockTest() {
    }

    private void print(){
        synchronized (SynchronizedStaticBlockTest.class){
            String name = Thread.currentThread().getName();
            for (int i = 0; i < 5; i++) {
                System.out.println("Hello " + name);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void print2(){
        synchronized (this){
            String name = Thread.currentThread().getName();
            for (int i = 0; i < 5; i++) {
                System.out.println("Print 2 Hello " + name);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {

        SynchronizedStaticBlockTest s1 = new SynchronizedStaticBlockTest();
        SynchronizedStaticBlockTest s2 = new SynchronizedStaticBlockTest();

        new Thread(() -> {
            System.out.println("Thread1 is start");
            s1.print2();
            System.out.println("Thread1 is end");

        }).start();

        new Thread(() -> {
            System.out.println("Thread2 is start");
            s2.print2();
            System.out.println("Thread2 is end");

        }).start();
    }
}

结果如下:

Thread1 is start
Print 2 Hello Thread-0
Thread2 is start
Print 2 Hello Thread-1
Print 2 Hello Thread-0
Print 2 Hello Thread-1
Print 2 Hello Thread-0
Print 2 Hello Thread-1
Print 2 Hello Thread-0
Print 2 Hello Thread-1
Print 2 Hello Thread-0
Print 2 Hello Thread-1
Thread1 is end
Thread2 is end

可以发现,Thread2没有等待Thread1执行完再执行,而是同时执行,说明当synchronized修饰代码块,作用对象是对象,那么只会锁当前对象。

为了方便大家记忆,我整理了一个表格来说明synchronized修饰普通方法、静态方法、代码块的作用域和作用对象。

修饰对象作用域        作用对象影响对象
普通方法整个方法对象当前对象
静态方法整个方法当前类
代码块-类整个代码块当前类及该类所有对象
代码块-对象整个代码块对象指定对象

下一篇,我们分析一下sychronized的底层原理。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/340208.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号