java关键字之synchronized

  1. synchronized是什么
    Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.
  2. synchronized解决什么问题
    在多线程环境中,当两个或多个线程尝试更新共享数据时,会发生竞争条件(race condition)。
    java提供一种机制来避免竞争条件的发生,就是synchronized关键字。
    举例:
    共享变量count,每个线程run方法count++ 10000次,10个线程操作共享变量的结果就应该是10 * 10000
    实际运行结果不是10 * 10000,小于10 * 10000而且每次运行结果都不同。
    原因分析:发生了竞争条件;假设当前count值为1000,线程1执行count++,线程2执行count++本应该是1000 +1 +1,但是实际上两个线程并发执行后,最终结果只是1001
//多线程的实现方式之一,实现Runnable接口并复写run方法
public class SynchronizedDemo implements Runnable{
    //共享变量
    private static int count = 0;
    public static void main(String[] args){
        //开启10个线程
        for(int i=0;i<10;i++){
            Thread t = new Thread(new SynchronizedDemo());
            t.start();
        }
        try {
            Thread.sleep(5000);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(count);
    }
    @Override
    public void run(){
            for(int i=0;i<10000;i++){
                count++;
            }
    }
}

  1. synchronized是如何使用的
    在java中synchronized可以用在代码块和方法中,根据使用的位置可以有如下使用场景:
    synchronized关键字的使用场景

举例1->静态方法

public class SynchronizedDemo1 implements Runnable{
    private static int count = 0;
    public static void main(String[] args){
        for(int i=0;i<10;i++){
            //不同对象,加在静态方法上
            Thread t = new Thread(new SynchronizedDemo1());
            t.start();
        }
        try {
            Thread.sleep(5000);

        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(count);
    }
    @Override
    public void run() {
        countIncrement();
    }

    public synchronized  static void countIncrement(){
        for(int i =0;i < 10000;i++){
            count++;
        }
    }
}

举例2->实例方法

public class SynchronizedDemo2 implements Runnable{
    private static int count = 0;
    public static void main(String[] args){
        SynchronizedDemo2 demo2 = new SynchronizedDemo2();
        for(int i=0;i<10;i++){
            //相同对象,加在对象实例方法上
            Thread t = new Thread(demo2);
            t.start();
        }
        try {
            Thread.sleep(5000);

        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(count);
    }
    @Override
    public void run() {
        countIncrement();
    }

    public synchronized void countIncrement(){
        for(int i =0;i < 10000;i++){
            count++;
        }
    }
}

举例3->代码块的实例对象

public class SynchronizedDemo3 implements Runnable{
    private static int count = 0;
    public static void main(String[] args){
        SynchronizedDemo3 demo3 = new SynchronizedDemo3();
        for(int i=0;i<10;i++){
            //相同对象,加在代码块锁this对象
            Thread t = new Thread(demo3);
            t.start();
        }
        try {
            Thread.sleep(5000);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(count);
    }
    @Override
    public void run() {
        synchronized (this){
            for(int i =0;i < 10000;i++){
                count++;
            }
        }
    }
}

举例4->代码块的class对象

public class SynchronizedDemo implements Runnable{
    private static int count = 0;
    public static void main(String[] args){
        for(int i=0;i<10;i++){
            //不同对象,加在代码块锁当前class对象
            Thread t = new Thread(new SynchronizedDemo());
            t.start();
        }
        try {
            Thread.sleep(5000);
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(count);
    }
    @Override
    public void run() {
        synchronized (SynchronizedDemo.class){
            for(int i=0;i<10000;i++){
                count++;
            }
        }
    }
}

举例5->任意实例对象Object

public class SynchronizedDemo4 implements Runnable{
    private static int count = 0;
    //任意实例对象
    private String lock = "lock";
    public static void main(String[] args){
        SynchronizedDemo4 demo4 = new SynchronizedDemo4();
        for(int i=0;i<10;i++){
            Thread t = new Thread(demo4);
            t.start();
        }
        try {
            Thread.sleep(5000);

        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println(count);
    }
    @Override
    public void run() {
        synchronized (lock){
            for(int i =0;i < 10000;i++){
                count++;
            }
        }
    }
}

4. synchronized有什么缺点
缺点:
①获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能等待,严重影响程序执行效率。
②场景:当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和读操作会发生冲突现象,但是读操作和读操作不会发生冲突现象。采用synchronized 关键字来实现同步的话,就会导致一个问题:如果多个线程都只是进行读操作,当一个线程在进行读操作时,其他线程只能等待无法进行读操作,这是不合理且非常影响效率。

解决办法:使用Lock在下一章节介绍

参考列表:
1、什么是race condition

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值