Synchronized

Synchronized:可以在任意对象上加锁,而加锁的这段代码称为互斥区或临界区。

public class SynchronizedDemo {
    /**
     * 线程不安全示例
     */
    class MyThread1 extends Thread{
        private int count = 5;

        @Override
        public void run() {
            count--;
            System.out.println(this.currentThread().getName()+":"+count);
        }
    }

    /**
     * synchronized修饰后实现的线程安全
     */
    class MyThread2 extends Thread{
        private int count = 5;

        @Override
        public synchronized void run() {
            count--;
            System.out.println(this.currentThread().getName()+":"+count);
        }
    }
    public static void test(Thread thread){
        String threadName = "thread";
        Thread[] threads = new Thread[5];
        for (int i = 0; i < 5; i++) {
            threads[i] = new Thread(thread,threadName+i);
        }
        for (Thread th : threads) {
            th.start();
        }
    }
}
使用MyThread1创建对象调用test使用MyThread2创建对象调用test
thread0:3
thread3:2
thread2:3
thread1:1
thread4:0
thread0:4
thread1:3
thread2:2
thread3:1
thread4:0

MyThread1和MyThread2的区别就是在run()方法上加上了synchronized修饰。
当多个线程访问run()方法时,如果使用了synchronized修饰,那么多个线程就会以排队的方式进行处理(cpu分配的先后顺序而定)。

synchronized作用于当前调用的对象
  1. synchronized修饰代码块
  2. synchronized修饰方法

演示代码:

public class Example1 {
    //synchronized修饰代码块
    public void test1(int j){
        synchronized (this){
            for (int i = 0; i < 10; i++) {
                System.out.println("test1 "+ j+ " : "+i);
            }
        }
    }
    //synchronized修饰方法
    public synchronized void test2(int j){
        for (int i = 0; i < 10; i++) {
            System.out.println("test2 "+ j+ " : "+i);
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Example1 example1 = new Example1();
        Example1 example2 = new Example1();
        executorService.execute(()->{
            example1.test1(1);
        });
        executorService.execute(()->{
            example1.test1(2);
        });
    }
}

当调用同一个对象时,输出结果为:
在这里插入图片描述

public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    Example1 example1 = new Example1();
    Example1 example2 = new Example1();
    executorService.execute(()->{
        example1.test1(1);
    });
    executorService.execute(()->{
        example2.test1(2);
    });
}

当调用同不同对象时,输出结果为:
在这里插入图片描述
因为synchronized修饰代码块、方法时,作用域是当前对象,所以当是两个对象同时调用时,会出现两个对象方法交替执行的情况。

synchronized作用于所有对象
  1. synchronized修饰静态方法
  2. synchronized修饰类
public class Example2 {
    //synchronized修饰类
    public void test1(int j){
        synchronized (Example2.class){
            for (int i = 0; i < 10; i++) {
                System.out.println("test1 "+ j+ " : "+i);
            }
        }
    }
    //synchronized修饰静态方法
    public synchronized static void test2(int j){
        for (int i = 0; i < 10; i++) {
            System.out.println("test2 "+ j+ " : "+i);
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        Example2 example1 = new Example2();
        Example2 example2 = new Example2();
        executorService.execute(()->{
            example1.test1(1);
        });
        executorService.execute(()->{
            example2.test1(2);
        });
    }
}

当synchronized修饰类、静态方法时,作用域是所有对象,所以当是两个对象同时调用时,这里就不会出现两个对象方法交替执行的情况。
在这里插入图片描述
注意:synchronized并不能被继承使用,因为synchronized非函数签名,因此无法被继承,所以无法保证子类调用同步.

synchronized可重入锁

当一个线程获得该对象的锁后,在该锁里执行代码的时候可以再次请求该对象的锁时,能再次获得该对象的锁。
即当线程请求一个由其他线程所持有的锁时,会阻塞;但是当它请求自身所持有的锁时,如果该锁是可重入锁,则会成功,否则会阻塞。

public class SynchronizedExample {
    public synchronized void method1(){
        System.out.println("method1...");
        method2();
    }
    public synchronized void method2(){
        System.out.println("method2...");
        method3();
    }
    public synchronized void method3(){
        System.out.println("method3...");
    }

    public static void main(String[] args) {
        SynchronizedExample demo = new SynchronizedExample();
        demo.method1();
    }
}

存在的意义:防止死锁的产生。

synchronized和volatile的区别

volatile关键字是强制从公共堆栈中取得变量的值,而不是线程私有的数据栈中取得变量值。
在这里插入图片描述

  1. volatile是线程同步的轻量级实现,性能比synchronized要好,并且volatile只能作用于变量,而synchronized可以修饰类,方法,代码块。
  2. 多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。
  3. volatile可以保证线程可见性,但不可以保证原子性;synchronized可以保证原子性,也可以间接保证可见性,因为,它会将工作内存与主内存中的数据做同步。
  4. volatile解决的是变量在多个线程之间的可见性,而synchronized解决的是多个线程间访问资源的同步性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值