Java中的线程--Lock和Condition实现线程同步通信
随着学习的深入,我接触了更多之前没有接触到的知识,对线程间的同步通信有了更多的认识,之前已经学习过synchronized 实现线程间同步通信,今天来学习更多的--Lock,GO!!!
一、初时Lock
Lock比传统线程模型中的synchronized更加面向对象,与生活中的锁类似,锁本身也应该是一个对象,两个线程执行的代码块要实现同步互斥的效果,他们必须用同一个lock对象,锁是上在代表要操作的资源类的背部方法中,而不是线程代码中。看一下具体的代码,如何使用Lock对象:
 public class LockTest {
     public static void main(String[] args) {
         new LockTest().init();
     }
     private void init() {
         outputer outputer = new outputer();
         new Thread(new Runnable() {
             @Override
             public void run() {
                 while (true) {
                     try {
                         Thread.sleep(10);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     outputer.output("songshengchao");
                 }
             }
         }).start();
         new Thread(new Runnable() {
             @Override
             public void run() {
                 while (true) {
                     try {
                         Thread.sleep(10);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     outputer.output("dongna");
                 }
             }
         }).start();
     }
     static class outputer {
      // 创建锁对象
         Lock lock = new ReentrantLock();
         public void output(String name) {
             int len = name.length();
        // 加上锁
             lock.lock();
             try {
                 for (int i = 0; i < len; i++) {
                     System.out.print(name.charAt(i));
                 }
                 System.out.println();
             }finally {
           // 释放锁
                 lock.unlock();
             }
         }
     }
二、读写锁
读写锁,分为读锁和写锁,多个读锁不互斥,读锁和写锁互斥,写锁与写锁互斥,这是由JVM自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但是不能同时写,那就上读锁。如果你的代码在修改数据,只能有一个人在写,并且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁。
看看代码中如何实现:
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockTest { public static void main(String[] args) { final Queue3 q3 = new Queue3();
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
q3.get();
}
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
while (true) {
q3.put(new Random().nextInt(10000));
} }
}).start();
}
} static class Queue3 { // 共享数据 只有一个线程可以写数据 多个线程读数据
private Object data = null;
// 读写锁对象
ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public void get() {
// 读锁 上锁
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " be ready to read ");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName() + " have read data " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 读锁 开锁
readWriteLock.readLock().unlock();
} } public void put(Object data) { // 写锁 上锁
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " be ready to write ");
Thread.sleep((long) (Math.random() * 1000));
this.data = data;
System.out.println(Thread.currentThread().getName() + " have write data " + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 写锁 开锁
readWriteLock.writeLock().unlock();
}
}
}
}
三、缓存系统的伪代码设计
这个jdk API文档中有一个很好的例子,就是在ReentrantReadWriteLock类中,具体可以自己看一下~
主要是读写锁的实际应用,你一定要思路清晰,具体代码如何执行,都要搞清楚,注释也比较详细,哈哈!代码如下:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; public class CacheDemo { private Map<String, Object> cache = new HashMap<String, Object>();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public static void main(String[] args) { } // 这个是获取缓存中数据的方法
public Object getData(String key) {
readWriteLock.readLock().lock();
Object value = null;
try {
value = cache.get(key);
// 如果多个线程同时执行数据库的查询 那就要执行多次数据库查询,浪费内存 可以加synchronized 上锁,但是用读写锁是更好的方法
if (value == null) {
// 这里代码就是从数据库中获取实际的相关数据,但是如果多线程的情况下呢?代码执行到这里,需要将从数据库中读取到的数据,写入到内存中
// 释放读锁
readWriteLock.readLock().unlock();
// 加上写锁,只能有一个线程进行写数据的操作
readWriteLock.writeLock().lock();
try {
// 预防多线程中同时进行写操作的线程进行数据的获取
if(value == null) {
value = "queryDB.getData()";
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 数据写进内存之后 释放写锁
readWriteLock.writeLock().unlock();
}
readWriteLock.readLock().lock();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
return value;
} }
四、Condition来实现线程间的通讯
Condition的功能类似在传统线程技术中的Object的wait()和notify()的功能。在等待Condition的时候,允许“虚假唤醒”,这通常作为基础平台语义的让步。对大多数应用程序来说,这带来的实际影响很小,因为Condition总是在一个循环中被等待。并测试正在等待的状态说明
注意:Condition是跟随Lock对象的
JDK 中 Condition类中的例子,经典中的经典:(JDK中的解释说明)
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
作为一个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用最佳规划,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。
代码如下:(这段代码其实挺不好理解的,为什么用两个Condition?)
  class BoundedBuffer {
    final Lock lock = new ReentrantLock();
    final Condition notFull  = lock.newCondition();
    final Condition notEmpty = lock.newCondition(); 
    final Object[] items = new Object[100];
    int putptr, takeptr, count;
    public void put(Object x) throws InterruptedException {
      lock.lock();
      try {
        while (count == items.length)
          notFull.await();
        items[putptr] = x;
        if (++putptr == items.length) putptr = 0;
        ++count;
        notEmpty.signal();
      } finally {
        lock.unlock();
      }
    }
    public Object take() throws InterruptedException {
      lock.lock();
      try {
        while (count == 0)
          notEmpty.await();
        Object x = items[takeptr];
        if (++takeptr == items.length) takeptr = 0;
        --count;
        notFull.signal();
        return x;
      } finally {
        lock.unlock();
      }
    }
  }
终极难题,实现两个以上线程同时交替运行的代码,condition类来实现,之前写那个两个线程交替运行的时候,试着写了一下,大于2个线程如何写,但是没有写出来,今天终于解决了那个问题,代码如下:
 public class ThreeConditionCommunication {
     public static void main(String[] args) {
         Business3 business = new Business3();
         // 线程2
         new Thread(new Runnable() {
             @Override
             public void run() {
                 for (int i = 1; i <= 50; i++) {
                     business.sub2(i);
                 }
             }
         }).start();
         // 线程3
         new Thread(new Runnable() {
             @Override
             public void run() {
                 for (int i = 1; i <= 50; i++) {
                     business.sub3(i);
                 }
             }
         }).start();
         // 本身main方法就是主线程,线程1 直接可以写循环代码
         for (int i = 1; i <= 50; i++) {
             business.main(i);
         }
     }
 }
 ---------------------------------------上面是测试代码----------------------------------------
 /**
  * 改造 用Condition实现三个线程间的通讯
  *
  * @author ssc
  *
  */
 public class Business3 {
     // 是否是子线程执行 默认子线程先执行 默认主线程先执行
     private int shouldSub = 1;
     private Lock lock = new ReentrantLock();
     private Condition condition1 = lock.newCondition();
     private Condition condition2 = lock.newCondition();
     private Condition condition3 = lock.newCondition();
     public void sub2(int i) {
         lock.lock();
         try {
             // 不是线程2应该执行 让给线程3 线程2执行等待的方法
             while (shouldSub != 2) {
                 // this.wait();
                 // Condition类特有的等待方法 await() 线程2等待
                 condition2.await();
             }
             for (int j = 1; j <= 10; j++) {
                 System.out.println("sub2 thread sequece of" + j + ", loop of " + i);
             }
             // 线程2执行完毕后 让给线程3执行
             shouldSub = 3;
             // 唤醒线程3
             // this.notify();
             // 等同于 notify()
             condition3.signal();
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }
     public void sub3(int i) {
         lock.lock();
         try {
             // 不是线程3应该执行 让给线程3 线程2执行等待的方法
             while (shouldSub != 3) {
                 // this.wait();
                 // Condition类特有的等待方法 await() 线程3等待
                 condition3.await();
             }
             for (int j = 1; j <= 20; j++) {
                 System.out.println("sub3 thread sequece of" + j + ", loop of " + i);
             }
             // 线程3执行完毕后 让给线程1 也就是主线程执行
             shouldSub = 1;
             // 唤醒线程1
             // this.notify();
             // 等同于 notify()
             condition1.signal();
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }
     public void main(int i) {
         lock.lock();
         try {
             // 是线程2应该执行 让给线程2执行 主线程执行等待的方法
             while (shouldSub != 1) {
                 //this.wait();
                 condition1.await();
             }
             for (int j = 1; j <= 100; j++) {
                 System.out.println("main thread sequece of" + j + ", loop of " + i);
             }
             // 主线程执行费完毕后 交给子线程执行
             shouldSub = 2;
             // 唤醒线程2
             //this.notify();
             condition2.signal();
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }
     }
 }
Java中的线程--Lock和Condition实现线程同步通信的更多相关文章
- java中synchronized与Lock的异同
		
本文转载自java中synchronized与Lock的异同 前言 synchronized和Lock通过互斥保障原子性,能够保护共享数据以实现线程安全,其作用包括保障原子性.可见性.有序性 常见问题 ...
 - 线程高级应用-心得5-java5线程并发库中Lock和Condition实现线程同步通讯
		
1.Lock相关知识介绍 好比我同时种了几块地的麦子,然后就等待收割.收割时,则是哪块先熟了,先收割哪块. 下面举一个面试题的例子来引出Lock缓存读写锁的案例,一个load()和get()方法返回值 ...
 - JAVA中synchronized和lock详解
		
目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug Lea.本文并不比较synchronize ...
 - Java中的锁——Lock和synchronized
		
上一篇Java中的队列同步器AQS 一.Lock接口 1.Lock接口和synchronized内置锁 a)synchronized:Java提供的内置锁机制,Java中的每个对象都可以用作一个实现同 ...
 - Java 中的锁——Lock接口
		
Java SE5之后,并发包中新增了Lock接口(以及相关实现类)用来实现锁功能.虽然它少了(通过synchronized块或者方法所提供的)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的操作性. ...
 - C++11中的mutex, lock,condition variable实现分析
		
本文分析的是llvm libc++的实现:http://libcxx.llvm.org/ C++11中的各种mutex, lock对象,实际上都是对posix的mutex,condition的封装.不 ...
 - Java中Synchronized和Lock的使用
		
Lock的锁定是通过代码实现的,而 synchronized 是在 JVM 层面上实现的 synchronized在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线 ...
 - Java并发指南4:Java中的锁 Lock和synchronized
		
Java中的锁机制及Lock类 锁的释放-获取建立的happens before 关系 锁是java并发编程中最重要的同步机制.锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消 ...
 - Java中synchronized和Lock的区别
		
synchronized和Lock的区别synchronize锁对象可以是任意对象,由于监视器方法必须要拥有锁对象那么任意对象都可以调用的方法所以将其抽取到Object类中去定义监视器方法这样锁对象和 ...
 
随机推荐
- HTML5  中的meter 标签的样式设置
			
meter { -webkit-appearance: none; position: relative; display: block; margin: 8px auto; width: 100px ...
 - 我叫mt3.2更新公告
			
1.增加装备合成功能 可以用材料将现有的75级紫装升级为80级紫装. 2.增加全新公会副本 增加新的公会副本:神庙外围.掉落可以进阶装备的材料. 3.增加全新个人副本 增加新的个人副本:奴隶市场. 4 ...
 - P4443 [COCI2017-2018#3] Dojave(线段树)
			
传送门 设\(lim=2^n-1\),对于一个区间\([l,r]\)来说,如果\(sum\neq lim\)且能换出\(x\)并换进\(y\)来,使得\(sum\bigoplus a_x\bigopl ...
 - web框架原理,http 协议
			
目录 web框架原理 web框架是什么东西 执行代码用浏览器访问一下 输出结果 http 协议 http 协议简介 http 协议概述 http 工作原理 http请求方法 http 状态码 url介 ...
 - Django框架的安装,项目创建
			
目录 Django框架的安装,项目创建 方法安装 Django版本选择 1.11.21(最新LTS版) django管理目录 命令行创建项目 django项目 命令行启动 (必须在项目文件下执行) p ...
 - 商务系统的构造思路(无源码!)+如何用jsp实现点击单选框内容显示在另一个jsp页面
			
敲码经验总结: 之前犯了一个错误就是,没有从底层开始学起,有啥问题,就直接博客园找源码,去CSDN找源代码,看到代码就复制粘贴,结果从新梳理知识点的时候,貌似除了复制粘贴,印象深刻的知识啥也没学到. ...
 - win10怎么修改DNS
			
方法/步骤 1 鼠标右键桌面单击此电脑--属性,如下图所示 2 进入电脑属性,选择控制面板主页,如下图所示 3 我们继续选择网络和Internet进入,如下图所示 4 进入网络和Internet, ...
 - POJ3744(概率dp)
			
思路:一长段概率乘过去最后会趋于平稳,所以因为地雷只有10个,可以疯狂压缩其位置,这样就不需要矩阵乘优化了.另外初始化f[0] = 0, f[1] = 1,相当于从1开始走吧.双倍经验:洛谷1052. ...
 - how browser supports https
			
1. pre-installed certificate authorities 2. ssl/tls encription ssl/tls handshake flow: 1. exchange d ...
 - 109 Convert Sorted List to Binary Search Tree 有序链表转换二叉搜索树
			
给定一个单元链表,元素按升序排序,将其转换为高度平衡的BST.对于这个问题,一个高度平衡的二叉树是指:其中每个节点的两个子树的深度相差不会超过 1 的二叉树.示例:给定的排序链表: [-10, -3, ...