zoukankan      html  css  js  c++  java
  • java 锁3

    先谈线程的状态:

    具体来说有,

    NEW、

    Running、

    Blocked、此状态的线程阻塞,它正在等待监视器锁——等待另外一个线程释放锁(通俗说就是等它执行完synchronized了的方法/代码块)。 就是说出现了资源争用的情况。引起Blocked的原因,不用说,现在很明了了: 多个线程想同时进入同一个同步代码块——第一个进入的自然不会Blocked,后面的就Blocked。。 同步代码块 的实现就不说了,一般就是synchronized、Lock。。

    Waiting、此状态的线程阻塞,它其实是在等待唤醒,就是重新获得锁(再通俗一点说就是获得失去过的。。。),引起Waiting的原因,就是由于调用了obj.wait导致失去了锁。。。 还有其他的吗?还有的!!:

      

      好吧,join、park之流具体为什么导致线程的wait就不说了,太复杂,搞不懂了。。。

    TIMED_WAITING、基本同上? no, 虽然和上面的状态都有wait,但是引起线程TIMED_WAITING的原因却大不相同!

    一般来说,TIMED_WAITING原因有:

      sleep

      LockSupport.parkNanos

      wait(time) ?

        举例:

          

      

    "main" prio=6 tid=0x0239c800 nid=0x3714 waiting on condition [0x01e7f000..0x01e7fe28]
       java.lang.Thread.State: TIMED_WAITING (sleeping)
            at java.lang.Thread.sleep(Native Method)
            at test.ObjectLock.main(ObjectLock.java:25)
    
    
    "RMI TCP Connection(idle)" daemon prio=6 tid=0x0515fc00 nid=0x2d10 waiting on condition [0x0574f000..0x0574fc68]
       java.lang.Thread.State: TIMED_WAITING (parking)
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x22ed03f8> (a java.util.concurrent.SynchronousQueue$TransferStack)
            at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
            at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
            at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
            at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
            at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
            at java.lang.Thread.run(Thread.java:619)
    
    
    
    "RMI TCP Connection(6)-10.0.0.23" daemon prio=6 tid=0x051b0400 nid=0x4d74 in Object.wait() [0x058fe000..0x058ffae8]
       java.lang.Thread.State: TIMED_WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on <0x22eee320> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)
            at com.sun.jmx.remote.internal.ArrayNotificationBuffer.fetchNotifications(ArrayNotificationBuffer.java:417)
            - locked <0x22eee320> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)
            at com.sun.jmx.remote.internal.ArrayNotificationBuffer$ShareBuffer.fetchNotifications(ArrayNotificationBuffer.ja
    va:209)
            at com.sun.jmx.remote.internal.ServerNotifForwarder.fetchNotifs(ServerNotifForwarder.java:258)
            at javax.management.remote.rmi.RMIConnectionImpl$2.run(RMIConnectionImpl.java:1227)
            at javax.management.remote.rmi.RMIConnectionImpl$2.run(RMIConnectionImpl.java:1225)
            at javax.management.remote.rmi.RMIConnectionImpl.fetchNotifications(RMIConnectionImpl.java:1231)
    View Code

    TERMINATED   这个就不说了。原因? 线程执行完了,run方法执行完了,或者被close ?

      

    关键是Blocked和Waiting的区别, 

    同:他们都导致了线程的阻塞(虽然说Blocked就是阻塞的意思,但是Waiting也是属于广义的阻塞),导致了线程不能继续执行,“卡住”了。

    异:解除Blocked需要的是获得对象的锁,具体来说是synchronized或Lock所在方法/代码块对应的对象。 而解除Waiting需要执行wait方法的对象再次执行notify/notifyAll。

    关联:两者其实可以理解为java提供的两种机制。 用法不同。

    关键点:

    1 锁,在java中是一直实实在在的对象,虽然但单从synchronized看不出哪里有new一个锁,但是java的底层机制确实是new了锁?并且关联在对应的线程之上。同时java还存在锁池的说法。而Lock, 则是显而易见了的new了锁。当然,两者的锁有所不同。

    2 这里的对象,其实可以理解为一种资源。

    3 wait、notify虽然不是直接的锁,但是和锁有千丝万缕的联系。 notify 可以唤醒等待在某对象的线程(亦即获得某对象的监视器)

    4 不明白的是为什么wait、notify的时候一定需要synchronized等用获得对应的锁

    5 对象的锁和对象的监视器 到底是什么概念, 怎么区分?

    参考

    http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.State.html

    http://www.cnblogs.com/lostyue/archive/2012/03/21/2410793.html

    Object 有提供 三个重构的wait、一个notify、一个notifAll 。 都是线程或者说多线程,相关的。

    Wait()方法,使当前获得指定对象锁的线程阻塞并释放锁。 ————我很好奇,为什么要阻塞,然后又释放呢?

    http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait()

    我明白了,其实这是一种奇怪的机制,

    synchronized (obj) {
             while (<condition does not hold>)
                 obj.wait();
             ... // Perform action appropriate to condition
         }

    synchronized(obj)等锁表明,使得线程执行时, 必须获得obj的锁。obj.wait()使得当期线程失去了锁(或者说释放了锁)。—— 既然释放了锁,而是synchronized又表明线程是需要锁的,—— 这样就导致了线程的阻塞—— 处于Waiting状态。—— 这种的阻塞的原因不同于不同线程同时进入synchronized方法/代码块引起的阻塞,Waiting—— 此时obj对象上应该是没有任何的监视器(或者说‘锁’),因为它之前获得过,失去的原因是它主动释放的锁。想要‘失去’得先‘有’才行——这样的机制使得synchronized有了存在性!!!!!!!!!

    Blocked——此时obj对象上应该是有且只有一个监视器(一个对象不能有多个监视器吧。。)

    —— 就是这样!!

    —— 既然如此,Waiting状态的线程对那个对象已经没有了监视器,是否可以被别的线程获得此对象监视器呢,然后导致该线程对obj执行notify失败? 可以这样!但是java规定notify的时候一定需要synchronized,不允许这种情况出现,也永远不会出现——这就解释了notify的时候一定需要synchronized等用获得对应的锁!!!!!!!!!!!!!!


    Notify、NotifyAll 使当前没有获得指定对象锁的线程唤醒。

    http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify()

    Notify的困惑之处在于,它是随机唤醒等待在该对象上的线程的,当然,如果只有一个线程等待,不会有随机的说法。

    为什么是‘随机’呢???

    方法调用一定要处于synchronized关键字包含的代码中,即锁控制的区域。

    package test;
    
    
    public class ObjectLock {
        
        
        public static void main(String[] args) {
    
            final SimpleBean bean = new SimpleBean();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    bean.aa();
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    bean.bb();
                }
            });
            
            t1.start();
            try {
                Thread.sleep(100000);// sleep1
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t2.start();
            
        }
    
        
    }
    
    class SimpleBean {
    
        public synchronized void aa() {
            System.out.println("SimpleBean.aa() start !");
            try {
                this.wait();//----------- 这里的wait并没有处于loop-condition之中, 这样写法有问题吗????
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("SimpleBean.aa() end !");
        }
        
        public synchronized  void bb() {
            System.out.println("SimpleBean.bb() 1");
            this.notify();
            System.out.println("SimpleBean.bb() 2");
        }
        
    }
    
    打印:
    SimpleBean.aa() start !
    SimpleBean.bb() 1
    SimpleBean.bb() 2
    SimpleBean.aa() end !


    新建线程的sleep1时候的堆栈:

    "Thread-0" prio=6 tid=0x02334400 nid=0x35fc in Object.wait() [0x047bf000..0x047bfb68]
    java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x22e74c10> (a test.SimpleBean)
    at java.lang.Object.wait(Object.java:485)
    at test.SimpleBean.aa(ObjectLock.java:41)
    - locked <0x22e74c10> (a test.SimpleBean)
    at test.ObjectLock$1.run(ObjectLock.java:13)
    at java.lang.Thread.run(Thread.java:619)

    名称: Thread-0
    状态:WAITING 在 test.SimpleBean@1f4cbee 上
    阻塞总数:0 等待总数: 1

    堆栈追踪:
    java.lang.Object.wait(Native Method)
    java.lang.Object.wait(Object.java:485)
    test.SimpleBean.aa(ObjectLock.java:41)
    test.ObjectLock$1.run(ObjectLock.java:13)
    java.lang.Thread.run(Thread.java:619)

    注:

    wait抛出非runtime Exception, 必须捕获; notify 则不是。

    wait、notify都必须被处于锁控制的区域,即一定要处于synchronized关键字或Lock的锁,包含的代码中。 否则就是 java.lang.IllegalMonitorStateException

    参考 http://www.cnblogs.com/xwdreamer/archive/2012/05/12/2496843.html 

    奇怪的是这么一句: 即使你确实知道当前上下文线程确实拥有了对象锁,也不能将object.wait()这样的语句写在当前上下文中

    如果改成这样:

    package test;
    
    
    public class ObjectLock {
        
        
        public static void main(String[] args) {
    
            final SimpleBean bean = new SimpleBean();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    bean.aa();
                }
            });
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    bean.bb();
                }
            });
            
            t1.start();
    //        try {
    //            Thread.sleep(100000);
    //        } catch (InterruptedException e) {
    //            e.printStackTrace();
    //        }
            t2.start();
            
        }
    
        
    }
    
    class SimpleBean {
    
        public synchronized void aa() {
            System.out.println("SimpleBean.aa() start !");
            try {
    //            this.wait();
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("SimpleBean.aa() end !");
        }
        
        public synchronized void bb() {
            System.out.println("SimpleBean.bb() 1");
            this.notify();
            System.out.println("SimpleBean.bb() 2");
        }
        
    }

    "Thread-1" prio=6 tid=0x02283000 nid=0x2be4 waiting for monitor entry [0x0483f000..0x0483fce8]
    java.lang.Thread.State: BLOCKED (on object monitor)
    at test.SimpleBean.bb(ObjectLock.java:50)
    - waiting to lock <0x229bdde8> (a test.SimpleBean)
    at test.ObjectLock$2.run(ObjectLock.java:19)
    at java.lang.Thread.run(Thread.java:619)

    "Thread-0" prio=6 tid=0x02280c00 nid=0x3a7c waiting on condition [0x047af000..0x047afd68]
    java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at test.SimpleBean.aa(ObjectLock.java:42)
    - locked <0x229bdde8> (a test.SimpleBean)
    at test.ObjectLock$1.run(ObjectLock.java:13)
    at java.lang.Thread.run(Thread.java:619)

    名称: Thread-0
    状态: TIMED_WAITING
    阻塞总数:0 等待总数: 1

    堆栈追踪:
    java.lang.Thread.sleep(Native Method)
    test.SimpleBean.aa(ObjectLock.java:42)
    - 已锁定 test.SimpleBean@d72200
    test.ObjectLock$1.run(ObjectLock.java:13)
    java.lang.Thread.run(Thread.java:619)

    名称: Thread-1
    状态:BLOCKED 在 test.SimpleBean@d72200 上,拥有者: Thread-0
    阻塞总数:1 等待总数: 0

    堆栈追踪:
    test.SimpleBean.bb(ObjectLock.java:50)
    test.ObjectLock$2.run(ObjectLock.java:19)
    java.lang.Thread.run(Thread.java:619)

    可以看到Wait 方法确实是释放了锁的? 使外层的synchronized失效?

    释放对象监控器的所有权,直到另外一个线程通过notify或notifyAll来唤醒。。。 

     <br>wait() <br>JDk文档写道 <br><br>在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。 <br><span style="">当前线程必须拥有此对象监视器</span> 。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

    而且此方法应始终在循环中使用 ?? 

    参考:http://www.360doc.com/content/12/1010/19/59141_240697086.shtml

     好难理解。。

    http://blog.sina.com.cn/s/blog_5ffe533a0101iw25.html

    wait、notify 等和synchronized的关系?

    重点:

    Object的wait、notify等方法是为了多线程之间协作而准备的!明白了这点,就不会有那么多纠结了吧.. !!

    2 Thread的sleep、interrupt、suspend、close。。。

  • 相关阅读:
    NTP时间同步
    《暗时间》
    寻找字典公共键
    maven pom.xml的execution报错
    maven安装scala插件
    html 和xml
    sparkstreaming+kafka
    zookeeper错误Error contacting service. It is probably not running.
    eclipse开发hive2程序
    eclipse开发hbase程序
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/3841994.html
Copyright © 2011-2022 走看看