• JAVA并发


    JAVA并发与厕所理论

    多个进程或线程同时(或着说在同一段时间内)访问同一资源会产生并发问题。用排队上厕所理论很好理解这个问题:人在上厕所时会占用当前厕位,其它要想用这个厕位的人就要等待。

    java 用synchronized解决同步问题

    1. 用法1
      public class Test{
          public synchronized void print(){
              ....;
          } 
      }
      

      某线程执行print()方法,则该对象将加锁。其它线程将无法执行该对象的所有synchronized块。用厕所时将整个厕所门锁住。

    2. 用法2
      public class Test{
          public void print(){
              synchronized(this){//锁住本对象
                  ...;
              }
          }
      }
      

      同用法1, 但更能体现synchronized用法的本质。

    3. 用法3
      public class Test{
          private String a = "test";
          public void print(){
              synchronized(a){//锁住a对象
                  ...;
              }
          }
          public synchronized void t(){
              ...; //这个同步代码块不会因为print()而锁定.
          }
      }
      

      执行print(),会给对象a加锁,注意不是给Test的对象加锁,也就是说 Test对象的其它synchronized方法不会因为print()而被锁。同步代码块执行完,则释放对a的锁。用厕所时锁住当前的厕位。


      为了锁住一个对象的代码块而不影响该对象其它 synchronized块的高性能写法:

      public class Test{
          private byte[] lock = new byte[0];
          public void print(){
              synchronized(lock){
                  ...;
              }
          }
          public synchronized void t(){
              ...; 
          }
      }
      
    4. 静态方法的锁
      public class Test{
          public synchronized static void execute(){
              ...;
          }
      }
      

      效果同

      public class Test{
          public static void execute(){
              synchronized(TestThread.class){
                  ...;
              }
          }
      }
      
      上厕时要所锁住所有的厕所。

    java wait、和notify 理解

    一般是执行完毕同步代码块(锁住的代码块)后就释放锁,也可以用wait()方式半路上释放锁。wait()方式就好比蹲厕所到一半,突然发现下水道堵住了,不得已必须出来站在一边,好让修下水道师傅(准备执行notify的一个线程)进去疏通马桶,疏通完毕,师傅大喊一声: "已经修好了"(notify),刚才出来的同志听到后就重新排队。注意啊,必须等师傅出来啊,师傅不出来,谁也进不去。也就是说notify后,不是其它线程马上可以进入封锁区域活动了,而是必须还要等notify代码所在的封锁区域执行完毕从而释放锁以后,其它线程才可进入。

    这里是wait与notify代码示例:

    public synchronized char pop() {
        char c;
        while (buffer.size() == 0) {
            try {
                this.wait(); //从厕位里出来
            } catch (InterruptedException e) {
                // ignore it...
            }
        }
        c = ((Character)buffer.remove(buffer.size()-1)).
            charValue();
        return c;
    }
    
    public synchronized void push(char c) {
        this.notify(); //通知那些wait()的线程重新排队。注意:仅仅是通知它们重新排队。
        Character charObj = new Character(c);
        buffer.addElement(charObj);
    }//执行完毕,释放锁。那些排队的线程就可以进来了。

    由于wait()操作而半路出来的同志没收到notify信号前是不会再排队的,他会在旁边看着这些排队的人(其中修水管师傅也在其中)。注意,修水管的师傅不能插队,也得跟那些上厕所的人一样排队,不是说一个人蹲了一半出来后,修水管师傅就可以突然冒出来然后立刻进去抢修了,他要和原来排队的那帮人公平竞争,因为他也是个普通线程。如果修水管师傅排在后面,则前面的人进去后,发现堵了,就wait,然后出来站到一边,再进去一个,再wait,出来,站到一边,只到师傅进去执行notify. 这样,一会儿功夫,排队的旁边就站了一堆人,等着notify.

    终于,师傅进去,然后notify了,接下来呢?

    1. 有一个wait的人(线程)被通知到。
    2. 为什么被通知到的是他而不是另外一个wait的人?取决于JVM.我们无法预先
       判断出哪一个会被通知到。也就是说,优先级高的不一定被优先唤醒,等待
       时间长的也不一定被优先唤醒,一切不可预知!(当然,如果你了解该JVM的
       实现,则可以预知)。
    3. 他(被通知到的线程)要重新排队。
    4. 他会排在队伍的第一个位置吗?回答是:不一定。他会排最后吗?也不一定。
       但如果该线程优先级设的比较高,那么他排在前面的概率就比较大。
    5. 轮到他重新进入厕位时,他会从上次wait()的地方接着执行,不会重新执行。
       恶心点说就是,他会接着拉巴巴,不会重新拉。
    6. 如果师傅notifyAll(). 则那一堆半途而废出来的人全部重新排队。顺序不可知。
     




  • 相关阅读:
    Array,prototype.toString.call()
    js 中的delete运算符
    c#连接sql数据库以及操作数据库
    ArrayList集合
    查找出数据表中的重复值
    C#中的List<string>泛型类示例
    C#中的List<string>泛型类示例
    C#中Convert.ToInt32、int.TryParse、(int)和int.Parse四者的区别
    C#获取文件夹下的所有文件的方法
    从本地文件夹中读取文本文档,并将所有的文档内容合并到一个文本中
  • 原文地址:https://www.cnblogs.com/doit8791/p/4619455.html
Copyright © 2020-2023  润新知