java核心学习(二十三) 多线程---线程同步

一、线程安全问题

  线程安全问题是由于代码在执行中的非原子性导致的。如果不能在程序上对线程访问临界区做出控制,则会“偶然出错”。

二、同步代码块

  同步监视器,实际上就是要访问的临界区,这个临界区是一个对象,下面代码obj就是同步监视器,在执行下面的代码时,会先获取obj的对象锁,如果该锁已经被其他线程占用,则当前线程阻塞。取得了对象锁之后就可以执行同步代码块里的代码,相当于PV原语中的互斥锁。

  

synchronized(obj)
{

    //对临界区obj进行访问的代码
}

三、同步方法

  在方法返回值定义之前使用sychronized关键字修饰,相当于同步监视器为this对象的同步代码块。

  使用同步方法可以很方便的实现线程安全的类,比如StringBuilder线程不安全,StringBuffer线程安全。

四、什么时候释放同步监视器的锁定

  代码无法显示释放,但是以下几种情况会导致线程释放对同步监视器的锁定:

  •     当前线程的同步方法、同步代码块执行结束,当前线程即释放同步监视器;
  •     当前线程在同步代码块遇到了break、return终止了该代码块、该方法的继续执行,当前线程会释放同步监视器;
  •     当前线程在同步代码块发生异常或错误,导致该代码块或该方法结束,会释放同步监视器;
  •     当前线程在执行同步代码块或同步方法时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步监视器;

  下面两种情况,线程不会释放同步监视器

  •   线程执行同步代码块或同步方法时,程序调用 Thread.sleep()、Thread.yield()方法来暂停或让步当前进程
  •   线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放同步监视器

五、同步锁(Lock)

  java5开始,可以通过显式定义同步锁对象(Lock)来实现同步,这种同步机制比简单的声明同步代码快更为灵活,线程开始访问临界区之前先获得Lock对象。

  java5中对同步锁设计了两个根接口Lock、ReadWriteLock(读写锁,可以解决读者写者问题,而读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。),并为Lock提供了ReentrantLock(可重入锁,可重入是指对于同一个锁对象,如果该线程已经获取该锁对象,则再次进入被该锁对象锁住的区域时依然可以进入)实现类,为ReadWriteock提供了ReentrantReadriteLock实现类。

  Synchronized实际上是一种可重入锁,通常会使用可重入锁来控制线程并发访问临界区。

  ReentrantLock锁具有可重入性,也就是说,一个线程可以对已被加锁的ReentrantLock锁再次加锁,ReentrantLock对象和会维持一个计数器来追踪lock()方法的嵌套调用,线程在每次调用lock()加锁后,必须显示调用unlock()来释放锁,所以一段被锁保护的代码可以调用另一个被相同锁保护的方法。

  

posted @ 2017-09-23 16:03  The_shy  阅读(207)  评论(0编辑  收藏  举报