高并发获取唯一性自增长字段

一、考虑使用synchronized同步锁

对synchronized(this)的一些理解

  1. 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
  2. 当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
  3. 然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的除synchronized(this)同步代码块以外的部分。
  4. 第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
  5. 以上规则对其它对象锁同样适用。

上述内容参考:http://hacker0825.blog.163.com/blog/static/3457067720106994054575/

一:synchronized同步代码块

package com.clzhang.sample.thread;

public class SyncThread1 implements Runnable {
    private Integer key = 0;

    @Override
    public void run() {
        // key是Integer对象(注意不是int,因为int不是对象)
        // 线程进入下面同步代码之前,需要先获取key的锁。
        // 需要结果是key实现自增长,如果没有同步块,则可能会出现重复key值的现象
        synchronized (key) {
            key++;

            System.out.println(Thread.currentThread().getName() + ":" + key);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
            }
        }
    }

    public static void main(String[] args) {
        SyncThread1 st = new SyncThread1();

        for(int i=0; i<10; i++) {
            new Thread(st, "Thread" + i).start();
        }
    }
}

输出:

Thread1:2
Thread3:3
Thread5:4
Thread7:5
Thread0:2
Thread2:7
Thread9:6
Thread4:8
Thread6:9
Thread8:10

二:synchronized同步方法

同步方法分静态和非静态两种。静态方法则一定会同步,非静态方法需在单例模式才生效,推荐用静态方法(不用担心是否单例)。

2.1 非静态方法同步示范

package com.clzhang.sample.thread;

// 如果是同步方法,则分静态和非静态两种。
// 静态方法则一定会同步,非静态方法需在单例模式才生效,推荐用静态方法(不用担心是否单例)。
public class SyncThread2 implements Runnable {
    private Integer key = 0;

    // 此示范为非静态方法同步
    public synchronized Integer getKey() {
        key++;

        return key;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":" + getKey());
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
        }
    }

    public static void main(String[] args) {
        // 非静态方法同步,需要启动单例模式
        SyncThread2 st = new SyncThread2();
        for (int i = 0; i < 10; i++) {
            new Thread(st, "Thread" + i).start();
        }
    }
}

输出:

Thread0:1
Thread1:3
Thread2:2
Thread3:5
Thread5:6
Thread7:7
Thread9:8
Thread6:9
Thread8:10
Thread4:4

2.2 静态方法同步示范

package com.clzhang.sample.thread;

// 如果是同步方法,则分静态和非静态两种。
// 静态方法则一定会同步,非静态方法需在单例模式才生效,推荐用静态方法(不用担心是否单例)。
public class SyncThread3 implements Runnable {
    private static Integer key = 0;

    // 此示范为静态方法同步
    public synchronized static Integer getKey() {
        key++;

        return key;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + ":" + getKey());
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
        }
    }

    public static void main(String[] args) {

        // 如果用静态方法实现同步,则可以生成对象的多个实例
        for (int i = 0; i < 10; i++) {
            SyncThread3 st = new SyncThread3();
            new Thread(st, "Thread" + i).start();
        }
    }
}

输出:

Thread3:3
Thread1:1
Thread0:2
Thread5:4
Thread7:5
Thread9:6
Thread2:7
Thread8:10
Thread6:9
Thread4:8

总结

1、无论是同步代码块还是同步方法,必须获得对象锁才能够进入同步代码块或者同步方法进行操作。

2、如果采用方法级别的同步,对象锁为方法所在的对象;如果是静态同步方法,对象锁为方法所在的类(唯一)。

3、对于代码块,对象锁即指synchronized(object)中的object。

二、使用java并发包

使用java.util.concurrent包来的较为简单,java.util.concurrent.atomic原子操作包,这个包里面提供了一组原子变量类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的,不会阻塞线程(或者说只是在硬件级别上阻塞了)。可以对基本数据、数组中的基本数据、对类中的基本数据进行操作。原子变量类相当于一种泛化的volatile变量,能够支持原子的和有条件的读-改-写操作。

java.util.concurrent.atomic中的类可以分成4组:

  • 标量类(Scalar):AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
  • 数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
  • 更新器类:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
  • 复合变量类:AtomicMarkableReference,AtomicStampedReference

第一组AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference这四种基本类型用来处理布尔,整数,长整数,对象四种数据,其内部实现不是简单的使用synchronized,而是一个更为高效的方式CAS (compare and swap) + volatile和native方法,从而避免了synchronized的高开销,执行效率大为提升。

下面以AtomicInteger示例:

/**
 * 来看AtomicInteger提供的接口。

//获取当前的值
 
 public final int get()
 
 //取当前的值,并设置新的值
 
  public final int getAndSet(int newValue)
 
 //获取当前的值,并自增
 
  public final int getAndIncrement() 
 
 //获取当前的值,并自减
 
 public final int getAndDecrement()
 
 //获取当前的值,并加上预期的值
 
 public final int getAndAdd(int delta)

测试代码:

public class AtomicIntegerDemo {
 public static void main(String[] args) {
  AtomicInteger ai=new AtomicInteger(0);
  int i1=ai.get();
  v(i1);
  int i2=ai.getAndSet(5);
  v(i2);
  int i3=ai.get();
  v(i3);
  int i4=ai.getAndIncrement();
  v(i4);
  v(ai.get());
  
 }
 static void v(int i)
 {
  System.out.println("i : "+i);
 }
}

时间: 2024-10-17 14:40:26

高并发获取唯一性自增长字段的相关文章

数据库高并发情况下重复值写入的避免 字段组合约束+ SQL SERVER 的SQL语句优化方式小结(转)

10线程同时操作,频繁出现插入同样数据的问题.虽然在插入数据的时候使用了: insert inti tablename(fields....) select @t1,@t2,@t3 from tablename where not exists (select id from tablename where [email protected],[email protected],[email protected]) 当时还是在高并发的情况下无效.此语句也包含在存储过程中.(之前也尝试线判断有无记

在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?

在高并发.高负载的情况下,如何给表添加字段并设置DEFAULT值? 在Oracle 12c之前,当Oracle表数据量上亿时,对表执行“ALTER TABLE XXX ADD COLUMN_XX VARCHAR2(2) DEFAULT 'XXX';”操作时,效率及安全性是必须要考虑的因素.若直接执行,则会在该过程中给表加上6级表锁,也就是连查询都需要等待,这在生产库上是相当危险的操作.因为Oracle在执行上述操作过程中,不仅要更新数据字典,还会刷新全部的记录,并且会使得Undo表空间暴涨,所以

如何在高并发分布式系统中生成全局唯一Id

我了解的方案如下-------------------------- 1.  使用数据库自增Id 优势:编码简单,无需考虑记录唯一标识的问题. 缺陷: 1)         在大表做水平分表时,就不能使用自增Id,因为Insert的记录插入到哪个分表依分表规则判定决定,若是自增Id,各个分表中Id就会重复,在做查询.删除时就会有异常. 2)         在对表进行高并发单记录插入时需要加入事物机制,否则会出现Id重复的问题. 3)         在业务上操作父.子表(即关联表)插入时,需要

如何在高并发分布式系统中生成全局唯一Id(转)

http://www.cnblogs.com/heyuquan/p/global-guid-identity-maxId.html 又一个多月没冒泡了,其实最近学了些东西,但是没有安排时间整理成博文,后续再奉上.最近还写了一个发邮件的组件以及性能测试请看 <NET开发邮件发送功能的全面教程(含邮件组件源码)> ,还弄了个MSSQL参数化语法生成器,会在9月整理出来,有兴趣的园友可以关注下我的博客. 分享原由,最近公司用到,并且在找最合适的方案,希望大家多参与讨论和提出新方案.我和我的小伙伴们也

MySQL面试必考知识点:揭秘亿级高并发数据库调优与最佳实践法则

做业务,要懂基本的SQL语句: 做性能优化,要懂索引,懂引擎: 做分库分表,要懂主从,懂读写分离... 数据库的使用,是开发人员的基本功,对它掌握越清晰越深入,你能做的事情就越多. 今天我们用10分钟,重点梳理一遍以下几方面: 数据库知识点汇总: 数据库事务特性和隔离级别: 详解关系型数据库.索引与锁机制: 数据库调优与最佳实践: 面试考察点及加分项. 知识点汇总 一.数据库的不同类型 1.常用的关系型数据库 Oracle:功能强大,主要缺点就是贵 MySQL:互联网行业中最流行的数据库,这不仅

[转]10分钟梳理MySQL知识点:揭秘亿级高并发数据库调优与最佳实践法则

转:https://mp.weixin.qq.com/s/RYIiHAHHStIMftQT6lQSgA 做业务,要懂基本的SQL语句: 做性能优化,要懂索引,懂引擎: 做分库分表,要懂主从,懂读写分离... 数据库的使用,是开发人员的基本功,对它掌握越清晰越深入,你能做的事情就越多. 今天我们用10分钟,重点梳理一遍以下几方面: 数据库知识点汇总: 数据库事务特性和隔离级别: 详解关系型数据库.索引与锁机制: 数据库调优与最佳实践: 面试考察点及加分项. 一.数据库的不同类型 1.常用的关系型数

高并发的核心技术-幂等的实现方案(转)

高并发的核心技术-幂等的实现方案 一.背景 我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果. 例如: 1. 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果. 2. 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱: 3. 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的: 4. 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题. 等等很多重要的情况,这些逻辑都需要幂等的特性来支持.

大数据量高并发的数据库优化

一.数据库结构的设计 如果不能设计一个合理的数据库模型,不仅会增加客户端和服务器段程序的编程和维护的难度,而且将会影响系统实际运行的性能.所以,在一个系统开始实施之前,完备的数据库模型的设计是必须的. 在一个系统分析.设计阶段,因为数据量较小,负荷较低.我们往往只注意到功能的实现,而很难注意到性能的薄弱之处,等到系统投入实际运行一段时间后,才发现系统的性能在降低,这时再来考虑提高系统性能则要花费更多的人力物力,而整个系统也不可避免的形成了一个打补丁工程. 所以在考虑整个系统的流程的时候,我们必须

高并发高流量网站架构详解

(推荐)高并发高流量网站架构详解 Web2.0的兴起,掀起了互联网新一轮的网络创业大潮.以用户为导 向的新网站建设概念,细分了网站功能和用户群,不仅成功的造就了一大批新生的网站,也极大的方便了上网的人们.但Web2.0以用户为导向的理念,使得新 生的网站有了新的特点--高并发,高流量,数据量大,逻辑复杂等,对网站建设也提出了新的要求. 本文围绕高并发高流量的网站架构设计问题,主要研究讨论了以下内容: 首先在整个网络的高度讨论了使用镜像网站,CDN内容分发网络等技术对负载均衡带来的便利及各自的优缺