博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
soa---java 多线程的---锁
阅读量:5095 次
发布时间:2019-06-13

本文共 5358 字,大约阅读时间需要 17 分钟。

       如今soa 与分布式计算已经成为互联网公司技术的标配

       那他包括的知识点应该熟悉了解。并以此为基础,去应用,调优各种soa的框架。

       包括例如以下的四点。是分布式的基础。

        a java 多线程 承接高吞吐量。

        b java nio 承接高并发,与交互协议的定制。

        c java 反射  完毕序列化与反序列化。

        d 设计模式的应用 保证应用的扩展性。

 接上篇

    

    由于说锁的原理比較的枯燥,得带着问题场景去说。才干看下去。才干研究下去。

      在Java中Lock接口比synchronized块的优势是什么?你须要实现一个高效的缓存。它同意多个用户读,但仅仅同意一个用户写,以此来保持它的完整性,你会如何去实现它?

  这里主要是要考察说lock与synchronized 的差别。

  1 利用cpu底层机制lock有读锁 与 写锁的区分。

  2 在于上下文的切换与锁的竞争的优化。

  3 关于死锁的避免

 

  Synchronized  仅仅是jvm里面自己的一个协议;

  而关于这个Lock 他的底层里面是有硬件支持的原子操作,各种cpu都支持的,各种平台也支持。假设须要具体理解。能够看看里面的源代码,里面有一个重要的类就是AbstractQueuedSynchronizer,  它是轮询处理。

  synchronized 在取不到锁的时候。会休眠一段时间。这样要说开销非常大。

当然这样的synchronized 内部是后面的版本号能够进行优化的。

 
1 利用cpu底层机制lock有读锁 与 写锁的区分。

    那实现上面题干的两种方式例如以下

synchronized样例

代码例如以下

 

public class SynchronizedMap
{ private final Map
map=new HashMap
(); public synchronized void put(K k,V v){ map.put(k, v); } public synchronized V get(K k){ return map.get(k); }
这样的排斥了 写/写,读/写 读/读。

对于lock,相关代码例如以下。

public class LockMap
{ private final Map
map=new HashMap
(); private final ReadWriteLock lock=new ReentrantReadWriteLock(); private final Lock r=lock.readLock(); private final Lock w=lock.writeLock(); public void put(K key,V value){ w.lock(); try { map.put(key, value); } catch (Exception e) { e.printStackTrace(); }finally{ w.unlock(); } } public V get(K key){ r.lock(); try { return map.get(key); } catch (Exception e) { e.printStackTrace(); }finally{ r.unlock(); } return null; } }
这样的排斥了 写/写 读/写 。

但读/读没有排斥。

也是就说读与读是多个线程能够同一时候读的。----能够做为读多写少的应用。

 2在于上下文的切换与锁的竞争的优化。

对于 synchronized 来说。

他仅仅有一个条件队列的。里面放着相应于不同类型的(也能够说是处理不同业务类型的)线程。那这时。你仅仅能notifyall

    。为了保证程序的正确,把全部的线程都叫起来,无论是不是你想要的业务类型的线程。这样的对于性能影响是很大的。比方10个线程在一个条件队列上等待,那么调用notifyAll 将唤醒全部的线程
   这个时候线程产生例如以下:
       a 它们会在锁上面产生竞争。
       b 它们竞争完了之后大部分又大部分wait了
         这两步。会导致了大量的线程上下文切换。

以及大量锁的竞争。

但这个lock是没问题的。他能够对于 不同的条件创建wait-set ,比方生产者消费者模式。生产者生产一个对象。这时想唤醒消费者。仅仅须要在对应的条件上面的wait set进行single.
对于线程安全的lock队列,与线程安全的synchronized stack代码

synchronized 代码例如以下

public class ProductStack {	private Product[] products=new Product[10];	private int index;			public synchronized void addProduct(Product product){		try {			while(index>=(products.length-1)){//须要又一次检查一下。条件推断s				System.out.println(" the product array is full ; "+Thread.currentThread().getName()+" is waiting");				wait();			}								products[index]=product;				index++;				notifyAll();//为了能启动消费线程 当然也唤醒了生产线程。		} catch (Exception e) {			e.printStackTrace();		}	}			public synchronized Product pop(){		Product product=null;		try {						while(index<=0){ //须要又一次检查一下。条件推断				System.out.println("the product array is empty ;"+Thread.currentThread().getName() +"is waiting");				wait();			}   			    index--; 			    product=products[index];				notifyAll();   //为了能启动 加入线程。 当然也唤醒了消费线程。		} catch (Exception e) {			e.printStackTrace();		}				return product;	}}

对于lock

import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ProductQueue
{ private final static int defaultSize=10; private final V[] queue; private int total; private int tail; private int head; private Lock lock=new ReentrantLock(); private Condition notEmpty=lock.newCondition(); private Condition notFull= lock.newCondition(); public ProductQueue(){ this(defaultSize); } public ProductQueue(int initialCapacity) { super(); this.queue = (V[])new Object[initialCapacity]; } public void push(V v) throws InterruptedException{ lock.lock(); try { while (isFull()) { notFull.await(); } queue[tail] = v; ++tail; if (tail == queue.length) tail = 0; total++; notEmpty.signal();//唤醒的是同一种类型的线程,不会浪费。 } finally{ lock.unlock(); } } public V pop() throws InterruptedException{ lock.lock(); try { while(isEmpty()){ notEmpty.await(); } V v=queue[head]; head++; if(head==queue.length)head=0; total--; notFull.signal();//唤醒的是同一种类型的线程,不会浪费。 return v; } finally{ lock.unlock(); } } public boolean isEmpty(){ return total==0; } public boolean isFull(){ return total==queue.length; } }

注解里面解释到了问题的根本。

               notifyall 时将全部的线程,生产者,消费者都唤醒了。而此时你仅仅想唤醒生产者,或者仅仅想唤醒消费者,让你胡子眉毛一把抓

3 关于死锁的避免

   产生死锁的本质:至少有两把以上的锁,每一个线程获取锁的方式不会一样。实际应用中会有例如以下3种情况,出现死锁

a  同一类对象
    第一个方法
       synchronized(LockA){
                synchronized(LockB){
                       }
         }
                                  
       第二个方法
              synchronized(LockB){
                   synchronized(LockA){
                             doSomeThing.......
                  }
             }
   以上情况的解决方式是。顺序不一样。把顺序搞一样就成。
  b 对于方法 public void A(SameObject a,SameObject b){
                            synchronized(a){
                                                 synchronized(b){
                                                                                                    doSomeThing.......
                                                        }
                                                            }
                        }
 这里会产生死锁的可能,原因是依据參数的顺序就能有可能被锁了。 这时能够用并发包里面的tryLock最简单         以上是在同一个类里面。

b  这样的情况,是在两个类里面。能够想象成为两个资源。
                       在类A里面的有一个a 方法是同步的。
                       在类B里面的有一个b 方法是同步的。
                       a 里面调b方法。

                       b 里面调a方法。
    这里就会产生死锁,由于获取锁的顺序不一样。 这样的情况的解决方式是,将方法上的全部的synchronized的都去掉,换成同步块。但同步块同是将传过来的资源。进行一个copy. 这个在并发包里面的有些集合能够參考的。

全局,分析锁的个数。获取的顺序。顺序好说,那怎么分析?

怎么去分析死锁呢?
a 争取用同步块,把不能同步方法。从业务角度保证开方式调用。

b 用线程堆栈信息来分析(kill -3)的方式。
c 对于业务的拆解。

理论上没有死锁,可是锁管理的资源。在线程处理的时候,占时太长,将业务就要进行重构了。

d 加一功能代码 代码例如以下    

ThreadMXBean tmx = ManagementFactory.getThreadMXBean();  long[] ids = tmx.findDeadlockedThreads();  if (ids != null) {     ThreadInfo[] infos = tmx.getThreadInfo(ids, true, true);     System.out.println("The following threads are deadlocked:");     for (ThreadInfo ti : infos) {        System.out.println(ti);     }    }

转载于:https://www.cnblogs.com/gcczhongduan/p/5368713.html

你可能感兴趣的文章
Object 类
查看>>
ECharts-初始化方法参数不能传入jquery对象
查看>>
vi配置
查看>>
分治算法(二)
查看>>
UVA-340 Master-Mind Hints
查看>>
Educational Codeforces Round 14 C. Exponential notation 数字转科学计数法
查看>>
Cache何时使用及使用方法
查看>>
多读书,读好书
查看>>
和Keyle一起学StrangeIoc – Acknowledgements
查看>>
Beizer 贝塞尔曲线移动
查看>>
Hive任务优化(1)
查看>>
this的使用、继承、super
查看>>
hadoop map(分片)数量确定
查看>>
关于初级java面试问题的一些整理 (部分转自他人)
查看>>
Jquery_Ajax文件上传
查看>>
Oauth 学习
查看>>
WMS
查看>>
自旋锁与读写锁
查看>>
linux开发工具之Makefile(下)
查看>>
多线程-Thread、Runnable 创建线程和调用过程分析
查看>>