synchronized的基本使用方法

本文深入解析Java中的synchronized关键字,探讨其在不同场景下的应用,包括代码块、方法及类级别的锁定机制,揭示多线程环境下资源共享与同步控制的原理。

synchronized 是java中的关键字,他可以声明在以下几种方式中

  1. 修饰一个代码块:被它修饰的代码变成一个同步代码。只作用在当前的对象
  2. 修饰在一个普通方法上(ps:非静态方法):作用范围这个方法,作用当前对象的这个方法上
  3. 修饰一个静态方法上:一个类无论被实例化多少次静态方法只有一个,作用范围这个方法,作用这个类和这个类所有的对象的这个方法
  4. 修饰在一个类上:作用范围 synchronized包裹的代码块,作用这个类的所有对象

修饰一个代码块

正例

  • 当一个线程访问一个对象里面的用synchronized(this)修饰同步代码块的时候其他线程会被阻塞
public class SynchronizedDemo {
    public static void main(String[] args) throws InterruptedException {
        SyncTest1 syncTest1 = new SyncTest1();
        new Thread(syncTest1, "A").start();
          // 这里让主线程睡眠是为了 让“A"线程 先执行
        Thread.sleep(10);
        new Thread(syncTest1, "B").start();
    }
}
class SyncTest1 implements Runnable {
    int count = 0;
    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 3; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
            }
        }
    }
}
  • 结果
线程:A打印共享变量count:0
线程:A打印共享变量count:1
线程:A打印共享变量count:2
线程:B打印共享变量count:3
线程:B打印共享变量count:4

反例

  • 当多个实例分别被多个线程执行,这个用synchronized(this)修饰的同步块就是失去意义
public class SynchronizedDemo {
    public static void main(String[] args) throws InterruptedException {
        SyncTest1 syncTest2 = new SyncTest1();
        // 这里让主线程睡眠是为了 让“A"线程 先执行
        new Thread(new SyncTest1(), "A").start();
        new Thread(new SyncTest1(), "B").start();
        new Thread(new SyncTest1(), "C").start();
        new Thread(new SyncTest1(), "D").start();
    }
}
class SyncTest1 implements Runnable {
    static int count = 0;
    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
            }
        }
    }
}
  • 反例结果
线程:D打印共享变量count:0
线程:D打印共享变量count:1
线程:D打印共享变量count:2
线程:D打印共享变量count:3
线程:D打印共享变量count:4
线程:C打印共享变量count:0  // 这里是有问题的
线程:C打印共享变量count:5
线程:C打印共享变量count:6
线程:C打印共享变量count:7
线程:C打印共享变量count:8
线程:A打印共享变量count:9
线程:B打印共享变量count:10
线程:B打印共享变量count:12
线程:A打印共享变量count:11
线程:B打印共享变量count:13
线程:A打印共享变量count:14
线程:B打印共享变量count:15
线程:A打印共享变量count:16
线程:B打印共享变量count:17
线程:A打印共享变量count:18

修饰一个普通方法

  • 当一个普通方法被 synchronized 声明,那么一个线程访问 同一个实例里的这个方法,其他线程就会被阻塞,修饰一个普通方法 只对当前对象有用
public class SynchronizedDemo2 {
    public static void main(String[] args) throws InterruptedException {
        SyncFun syncFun1 = new SyncFun();
        new Thread(syncFun1, "A").start();
        // 这里让主线程睡眠是为了 让“A"线程 先执行
        Thread.sleep(10);
        new Thread(syncFun1, "B").start();
    }
}
class SyncFun implements Runnable {
    int count = 0;
    @Override
    public void run() {
        syncFun();
    }
    private synchronized void syncFun(){
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
        }
    }
}
  • 结果
线程:A打印共享变量count:0
线程:A打印共享变量count:1
线程:A打印共享变量count:2
线程:B打印共享变量count:3
线程:B打印共享变量count:4
线程:B打印共享变量count:5
  • 如果多个实例被多个线程访问那么这个锁是没有效果的,效果和上面的同步代码块里面的反例是一样的这里就不做展示了
  • 如果多个线程分别访问这个这个对象里的其他非同步方法会不会阻塞呢? 答案是不会的

开始测试

public class SynchronizedDemo2 {
    public static void main(String[] args) throws InterruptedException {
        SyncFun syncFun1 = new SyncFun();
        new Thread(syncFun1, "A").start();
        // 这里让主线程睡眠是为了 让“A"线程 先执行
        Thread.sleep(10);
        new Thread(syncFun1, "B").start();
        new Thread(syncFun1, "C").start();
    }
}
class SyncFun implements Runnable {
    static int count = 0;
    @Override
    public void run() {
        if("C".equals(Thread.currentThread().getName())){
            fun();
        }else{
            syncFun();
        }
    }
    private void fun() {
        for (int i = 0; i < 3 ; i++) {
            try {
                // 这里睡眠是为了不让这个线程很快的跑完,因为线程“A"设置了睡眠
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName()+ "我是不会被锁住的,我要读取共享变量count" + count);
        }
    }
    private synchronized void syncFun(){
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
        }
    }
}
  • 结果
线程:A打印共享变量count:0
线程:C我是不会被锁住的,我要读取共享变量count1
线程:A打印共享变量count:1
线程:C我是不会被锁住的,我要读取共享变量count2
线程:A打印共享变量count:2
线程:C我是不会被锁住的,我要读取共享变量count3
线程:B打印共享变量count:3
线程:B打印共享变量count:4
线程:B打印共享变量count:5

修饰一个静态方法

  • 当一个静态方法被一个线程访问 ,其他线程都会被阻塞。无论这个有多少个对象
public class SynchronizedDemo3 {
    public static void main(String[] args) throws InterruptedException {
        new Thread(new SyncStaticFun(), "A").start();
        // 这里让主线程睡眠是为了 让“A"线程 先执行
        Thread.sleep(10);
        new Thread(new SyncStaticFun(), "B").start();
    }
}

class SyncStaticFun implements Runnable {
    static int count = 0;
    @Override
    public void run() {
        syncStaticFun2();
    }
    private synchronized static void syncStaticFun2() {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
        }
    }
}
  • 结果
线程:A打印共享变量count:0
线程:A打印共享变量count:1
线程:A打印共享变量count:2
线程:B打印共享变量count:3
线程:B打印共享变量count:4
线程:B打印共享变量count:5

修饰一个类

  • synchronized (A.class)修饰在一个类上,作用范围在这个同步块上,作用在这个类的全部对象
public class SynchronizedDemo4 {
    public static void main(String[] args) {
        new Thread(new SyncClass(),"A").start();
        new Thread(new SyncClass(),"B").start();
        new Thread(new SyncClass(),"C").start();
    }
}

class SyncClass implements Runnable {
    private static int count = 0;
    @Override
    public void run() {
        synchronized (SyncClass.class) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
            }
        }

    }
    private void test1(){
        
    }

    private void test2(){

    }
}
  • 结果
线程:C打印共享变量count:0
线程:A打印共享变量count:1  // 有问题的
线程:B打印共享变量count:1
线程:C打印共享变量count:2
线程:A打印共享变量count:4
线程:B打印共享变量count:3
线程:C打印共享变量count:5
线程:A打印共享变量count:7
线程:B打印共享变量count:6
线程:C打印共享变量count:8
线程:B打印共享变量count:9
线程:A打印共享变量count:10
线程:C打印共享变量count:11
线程:B打印共享变量count:12
线程:A打印共享变量count:13
  • 如果这个synchronized修饰一个类,那么将这个类设置多把锁会不会有问题呢?是不会的 这两个线程会顺序执行
public class SynchronizedDemo4 {
    public static void main(String[] args) {
        new Thread(new SyncClass(),"A").start();
        new Thread(new SyncClass(),"B").start();
    }
}
class SyncClass implements Runnable {
    private static int count = 0;
    @Override
    public void run() {
        if("A".equals(Thread.currentThread().getName())){
            test1();
        }else{
            test2();
        }

    }
    private void test1(){
        synchronized (SyncClass.class) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
            }
        }
    }
    private void test2(){
        synchronized (SyncClass.class) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
            }
        }
    }
}
  • 结果
线程:B打印共享变量count:0
线程:B打印共享变量count:1
线程:B打印共享变量count:2
线程:B打印共享变量count:3
线程:B打印共享变量count:4
线程:A打印共享变量count:5
线程:A打印共享变量count:6
线程:A打印共享变量count:7
线程:A打印共享变量count:8
线程:A打印共享变量count:9
  • 如果synchronized修饰在一个类上,然后调用没有加锁的方法,共享变量是有问题的
public class SynchronizedDemo4 {
    public static void main(String[] args) {
        new Thread(new SyncClass(), "A").start();
        new Thread(new SyncClass(), "B").start();
    }
}

class SyncClass implements Runnable {
    private static int count = 0;

    @Override
    public void run() {
        if ("A".equals(Thread.currentThread().getName())) {
            test1();
        } else {
            test2();
        }

    }
    private void test1() {
        synchronized (SyncClass.class) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
            }
        }
    }

    private void test2() {
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程:" + Thread.currentThread().getName() + "打印共享变量count:" + count++);
        }
    }
}
  • 结果
线程:A打印共享变量count:0
线程:B打印共享变量count:1
线程:A打印共享变量count:2
线程:B打印共享变量count:3
线程:B打印共享变量count:4
线程:A打印共享变量count:5
线程:A打印共享变量count:6
线程:B打印共享变量count:6 // 有问题
线程:B打印共享变量count:7
线程:A打印共享变量count:8
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值