实例讲解Java中的synchronized

一、使用场景

在负责后台开发的时候,很多时候都是提供接口给前端开发人员去调用,会遇到这样的场景:

需要提供一个领奖接口,每个用户名只能领取一次,我们可以将成功领取的用户在数据库用个标记保存起来。如果这个用户再来领取的时候,查询数据库看该用户是否领取过。

但是问题来了,假设用户手速很快,极短时间内点了两次领奖按钮(前端没有进行控制,我们也不能依赖前端去控制)。那么可能掉了两次领奖接口,而且有可能第二次调用的时候查询数据库的时候,第一次领奖还没有执行完成更新领奖标记。

这种场景就可以使用到synchronized

二、使用实例

代码:

package com.luo.test;

public class SynTest {

  public static void main(String args[]) throws InterruptedException{
    SynTest synTest = new SynTest();
    synTest.test();
  }

  public void test() throws InterruptedException{
    new SynThread1().start();
    new SynThread1().start();
  }

  public void syn(String userName) throws Exception {
    synchronized(userName) {
      System.out.println("进入到同步块,userName=" + userName);
      Thread.sleep(5000); //5秒
      System.out.println("退出同步块,userName=" + userName);
    }
  }

  class SynThread1 extends Thread {
    public void run(){
      try {
        syn("luoguohui");
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
}

运行结果:

从结果来看,可知道,synchronized起作用了,这里调用了两次syn(String userName)方法,期间设置其停留5秒,但是还是等第一次执行完,第二次调用才进入synchronized块里面的。

为了进一步确认我们的假设,我们不防把synchronized去掉如下:

  public void syn(String userName) throws Exception {
//   synchronized(userName) {
      System.out.println("进入到同步块,userName=" + userName);
      Thread.sleep(5000); //5秒
      System.out.println("退出同步块,userName=" + userName);
//   }
  }

运行结果:

对比即可分析出来了

使用方式从实例可看出来:

public void syn(String userName) throws Exception {
  synchronized(userName) {
    System.out.println("进入到同步块,userName=" + userName);
    Thread.sleep(5000); //5秒
    System.out.println("退出同步块,userName=" + userName);
  }
}

用synchronized把代码括起来。

以上就是实例讲解Java中的synchronized的详细内容,更多关于Java synchronized的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java使用synchronized修饰方法来同步线程的实例演示

    Java中可以使用关键字synchronized进行线程同步控制,实现关键资源顺序访问,避免由于多线程并发执行导致的数据不一致性等问题.synchronized的原理是对象监视器(锁),只有获取到监视器的线程才能继续执行,否则线程会等待获取监视器.Java中每个对象或者类都有一把锁与之相关联,对于对象来说,监视的是这个对象的实例变量,对于类来说,监视的是类变量(一个类本身是类Class的对象,所以与类关联的锁也是对象锁).synchronized关键字使用方式有两种:synchronized方法

  • java synchronized加载加锁-线程可重入详解及实例代码

    java synchronized加载加锁-线程可重入 实例代码: public class ReGetLock implements Runnable { @Override public void run() { get(); } public synchronized void get() { System.out.println(Thread.currentThread().getId()); set(); } public synchronized void set() { Syste

  • Java 同步锁(synchronized)详解及实例

    Java 同步锁(synchronized)详解及实例 Java中cpu分给每个线程的时间片是随机的并且在Java中好多都是多个线程共用一个资源,比如火车卖票,火车票是一定的,但卖火车票的窗口到处都有,每个窗口就相当于一个线程,这么多的线程共用所有的火车票这个资源.如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票是一样的(座位号一样),这样就会给乘客造成麻烦.比如下面程序: package com.pakage.ThreadAndRunnable; public class Ru

  • 实例解析Java中的synchronized关键字与线程安全问题

    首先来回顾一下synchronized的基本使用: synchronized代码块,被修饰的代码成为同步语句块,其作用的范围是调用这个代码块的对象,我们在用synchronized关键字的时候,能缩小代码段的范围就尽量缩小,能在代码段上加同步就不要再整个方法上加同步.这叫减小锁的粒度,使代码更大程度的并发. synchronized方法,被修饰的方法成为同步方法,其作用范围是整个方法,作用对象是调用这个方法的对象. synchronized静态方法,修饰一个static静态方法,其作用范围是整个

  • Java多线程程序中synchronized修饰方法的使用实例

    在Java 5以前,是用synchronized关键字来实现锁的功能. synchronized关键字可以作为方法的修饰符(同步方法),也可作用于函数内的语句(同步代码块). 掌握synchronized,关键是要掌握把那个东西作为锁.对于类的非静态方法(成员方法)而言,意味着要取得对象实例的锁:对于类的静态方法(类方法)而言,要取得类的Class对象的锁:对于同步代码块,要指定取得的是哪个对象的锁.同步非静态方法可以视为包含整个方法的synchronized(this) { - }代码块.  

  • 实例讲解Java中的synchronized

    一.使用场景 在负责后台开发的时候,很多时候都是提供接口给前端开发人员去调用,会遇到这样的场景: 需要提供一个领奖接口,每个用户名只能领取一次,我们可以将成功领取的用户在数据库用个标记保存起来.如果这个用户再来领取的时候,查询数据库看该用户是否领取过. 但是问题来了,假设用户手速很快,极短时间内点了两次领奖按钮(前端没有进行控制,我们也不能依赖前端去控制).那么可能掉了两次领奖接口,而且有可能第二次调用的时候查询数据库的时候,第一次领奖还没有执行完成更新领奖标记. 这种场景就可以使用到synch

  • 实例讲解Java中random.nextInt()与Math.random()的基础用法

    1.来源 random.nextInt() 为 java.util.Random类中的方法: Math.random() 为 java.lang.Math 类中的静态方法. 2.用法 产生0-n的伪随机数(伪随机数参看最后注解): // 两种生成对象方式:带种子和不带种子(两种方式的区别见注解) Random random = new Random(); Integer res = random.nextInt(n); Integer res = (int)(Math.random() * n)

  • 实例讲解Java中动态代理和反射机制

    反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). 静态代理 预先(编译期间)确定了代理者与被代理者之间的关系,也就是说,若代理类在程序运行前就已经存在了,这种情况就叫静态代理 动态代理 代理类在程序运行时创建的代理方式.也就是说,代理类并不是在Java代码中定义的,而是在运行期间根据我们在Java代码中的"指示"动态生成的. 动态代理比

  • 实例讲解JAVA 模板方法模式

    在讲述这个模式之前,我们先看一个案例:抄题目:两个学生将老师出的题目抄写在纸上,并且写出答案 先看一个比较笨的写法 public class TestPaperA { public void testQuestion1(){ System.out.println("1+1等于几? a.1 b.2 c.3 d.4"); System.out.println("答案:b"); } public void testQuestion2(){ System.out.print

  • 实例讲解JAVA 适配器模式

    在讲述这个模式之前,我们先看一个案例:中国球员去NBA打篮球 中国球员去NBA打篮球,可是他不懂英语,所以听不懂教练安排的战术,所以现在有三种解决方式 1.球员学会英语.2.教练学会中文.3.请个翻译. 1和2是长久之计,但不能解决迫在眉睫的问题.请个翻译是短暂的更好的选择. 放在软件设计层面上,这就叫做适配器模式.https://www.jb51.net/article/189484.htm 将一个类的接口转换成客户希望的另外一个接口.适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以

  • 实例讲解JAVA设计模式之备忘录模式

    在讲述这个模式之前,我们先看一个案例:游戏回档 游戏的某个场景,一游戏角色有生命力.攻击力.防御力等数据,在打Boss前和后会不一样,我们允许玩家如果感觉与Boss决斗的效果不理想,可以让游戏恢复到决斗前.下面是代码: 游戏角色类,用来存储角色的生命力.攻击力.防御力的数据. public class GameRole { private int vit;//生命力 private int atk;//攻击力 private int def;//防御力 //状态显示 public void st

  • 实例讲解Java HashSet

    HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合. HashSet 允许有 null 值. HashSet 是无序的,即不会记录插入的顺序. HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的. 您必须在多线程访问时显式同步对 HashSet 的并发访问. HashSet 实现来 Set 接口. HashSet 中的元素实际上是对象,一些常见的基本类型可以使用它的包装类. 基本类型对应的包装类表如下: 基本类型 引用类型

  • 简单讲解java中throws与throw的区别

    Java中throws和throw的区别讲解 当然,你需要明白异常在Java中式以一个对象来看待. 并且所有系统定义的编译和运行异常都可以由系统自动抛出,称为标准异常,但是一般情况下Java 强烈地要求应用程序进行完整的异常处理,给用户友好的提示,或者修正后使程序继续执行. 直接进入正题哈: 1.用户程序自定义的异常和应用程序特定的异常,必须借助于 throws 和 throw 语句来定义抛出异常. 1.1   throw是语句抛出一个异常. 语法:throw (异常对象);         

  • 实例讲解Java 自旋锁

    一直以来不是怎么清楚自旋锁,最近有点时间,好好的学习了一下: 所谓的自旋锁在我的理解就是多个线程在尝试获取锁的时候,其中一个线程获取锁之后,其他的线程都处在一直尝试获取锁的状态,不会阻塞!!!那么什么叫做一直尝试获取锁呢?就是一个循环,比较经典的是AtomicInteger中的一个updateAndGet方法,下图所示(当然也可以直接看unsafe类中的getAndAddInt等类似方法): 我们可以看出在while循环中使用CAS去尝试更新一个变量,如果更新失败,就会一直在这个循环中一直在尝试

随机推荐