java项目——java中线程共享数据同步解决办法

来源:互联网 发布:2013蛇年新疆网络春晚 编辑:程序博客网 时间:2024/06/01 11:07

        我们开发项目时要经常和数据库打交道,用户的每一个操作基本上都和数据库息息相关。在涉及到共享资源

时,不同的线程对数据库的访问会造成数据的混乱。为了保证数据的安全性,所以要保证同一时刻只能允许一个用户

对数据库的同一个字段进行操作。要实现上述的描述,以下两种方法可以很好的解决该问题。

 


1.java synchronized关键字

 

概念


        Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时

刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内

只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线

程访问object的一个加锁代码块时,另一个线程仍然可以访问该object中的非加锁代码块。

 

分类

 

        (1)synchronized 方法:方法声明时使用,放在范围操作符(public等)之后,返回类型声明(void等)之前.这时,线

程获得的是成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是

在synchronized方法内部的线程)执行完该方法后,别的线程才能进入.


        synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句

块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class

literals(类名称字面常量)身上。

//格式:public synchronized void synMethod(){//方法体}


 

//实例//当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。package ths;public class Thread1 implements Runnable {       public void run() {            synchronized(this) {                 for (int i = 0; i < 5; i++) {                      System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);                 }            }       }       public static void main(String[] args) {            Thread1 t1 = new Thread1();            Thread ta = new Thread(t1, "A");            Thread tb = new Thread(t1, "B");            ta.start();            tb.start();       } }结果:       A synchronized loop 0       A synchronized loop 1       A synchronized loop 2       A synchronized loop 3       A synchronized loop 4       B synchronized loop 0       B synchronized loop 1       B synchronized loop 2       B synchronized loop 3       B synchronized loop 4


       (2)synchronized代码块,后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块.此时,线程获得的是

成员锁。

//例如:public Object synMethod(Object a1){synchronized(a1){//一次只能有一个线程进入}}


 

//实例:package ths;public class Thread2 {       public void m4t1() {            synchronized(this) {                 int i = 5;                 while( i-- > 0) {                      System.out.println(Thread.currentThread().getName() + " : " + i);                      try {                           Thread.sleep(500);                      } catch (InterruptedException ie) {                      }                 }            }       }           public static void main(String[] args) {            final Thread2 myt2 = new Thread2();            Thread t1 = new Thread(  new Runnable() {  public void run() {  myt2.m4t1();  }  }, "t1"  );            Thread t2 = new Thread(  new Runnable() {  public void run() { myt2.m4t1();   }  }, "t2"  );            t1.start();            t2.start();       } }结果:       t1 : 4       t1 : 3       t1 : 2       t1 : 1           t2 : 4       t2 : 3       t2 : 2       t2 : 1  


 

特点

 

        1).当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线

程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
        2).然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中

的非synchronized(this)同步代码块。
        3).尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其

它synchronized(this)同步代码块的访问将被阻塞。
        4).第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码

块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。


执行原则

 

        同步块中的代码执行的时间越短越好。

 

2.数据库机制


        悲观锁(Pessimistic Lock)

        顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别

人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,

读锁,写锁等,都是在做操作之前先上锁。


 

 

使用方法

 

//锁在用户修改之前就发挥作用: Select ..for update(nowait) Select * from tab1 for update 


            用户发出这条命令之后,数据库(不是局限于orecal中的数据库)将会对返回集中的数据建立行级封锁,以防止

其他用户的修改。 如果此时其他用户对上面返回结果集的数据进行dml或ddl操作都会返回一个错误信息或发生阻

塞。

        乐观的认为数据在select出来到update进取并提交的这段时间数据不会被更改。这里面有一种潜在的危险就是

由于被选出的结果集并没有被锁定,是存在一种可能被其他用户更改的可能。因此Oracle仍然建议是用悲观封锁,因

为这样会更安全。

       

        以上是个人目前的一些理解,如果大家有不同的理解我们可以加以交流。


 

1 0
原创粉丝点击