弱鸡绿毛怪
本帖最后由 MagicLocyDragon 于 2018-3-24 15:45 编辑

如何玩♂多线程——(3)线程基础下

前几章都完全没有排版,这次加了一个小排版(233)

首先我们这个帖子里要讲的内容是wait() notify() 以及 notifyAll()方法
不难发现 这三个方法均是Object类下的方法
这三个方法是什么意思呢?分别来解释一下。
调用某个对象的wait()方法可以让当前的线程堵塞,并且该线程必须持有此对象的monitor,注意,wait()方**释放目标对象的锁,而区别于Thread类下sleep()方法就是它不会释放任何东西。

调用某个对象的notify()方法可以唤醒等待当前monitor的线程,但是如果是多个线程都在等待,那么问题就来了
假设有A B C三个线程都在等待当前的monitor对象,而调用这个monitor对象仅仅会随机唤醒ABC三个线程中的一个。

调用某个对象的notifyAll()方法即是唤醒当前所有等待此monitor的线程
下面,我举一个使用了这三个方法的实例


实例

由于太懒,这一段是在网上随便找过来的。
    class NumberPrint implements Runnable{  
        private int number;  
        public byte res[];  
        public static int count = 5;  
        public NumberPrint(int number, byte a[]){  
            this.number = number;  
            res = a;  
        }  
        public void run(){  
            synchronized (res){  
                while(count-- > 0){  
                    try {  
                        res.notify();//唤醒等待res资源的线程,把锁交给线程(该同步锁执行完毕自动释放锁)  
                        System.out.println(" "+number);  
                        res.wait();//释放CPU控制权,释放res的锁,本线程阻塞,等待被唤醒。  
                        System.out.println("------线程"+Thread.currentThread().getName()+"获得锁,wait()后的代码继续运行:"+number);  
                    } catch (InterruptedException e) {  
                        // TODO Auto-generated catch block  
                        e.printStackTrace();  
                    }  
                }//end of while  
                return;  
            }//synchronized  
              
        }  
    }  
    public class WaitNotify {  
        public static void main(String args[]){  
            final byte a[] = {0};//以该对象为共享资源  
            new Thread(new NumberPrint((1),a),"1").start();  
            new Thread(new NumberPrint((2),a),"2").start();  
        }  
    }  

输出结果:
     1  
     2  
    ------线程1获得锁,wait()后的代码继续运行:1  
     1  
    ------线程2获得锁,wait()后的代码继续运行:2  
     2  
    ------线程1获得锁,wait()后的代码继续运行:1  
     1  
    ------线程2获得锁,wait()后的代码继续运行:2  


补充说明

比起使用wait()和notify()方法,我更喜欢使用 LockSupport类下的 park() 静态方法 和 unpark(Thread thread)静态方法,为什么?因为这两个方法比起wait()和notify()方**方便的多,大家也能一眼看出来为什么方便的多了。

如何使用?
在线程里调用静态方法 LockSupport.park(); 挂起当前线程
要唤醒线程时只需要调用方法 LockSupport.unpark(Thread thread); 即可唤醒

LockSupport类的实现

好奇的人估计都去研究了一下LockSupport类的源码吧,没错,LockSupport类的park方法的实现很简单,就是调用了

Unsafe.park();
即Unsafe类下的park方法

Unsafe类是什么?
unsafe类在
sun.misc.Unsafe 这里,研究一下Unsafe类的源码,不难发现,这个类下有很多神奇的方法,比如类似与C++的指针操作等,java其实是不让开发者们去使用这个类的,是因为这个类全都是本地方法,不够安全:
public static Unsafe getUnsafe() {
    Class var0 = Reflection.getCallerClass();
    if(!VM.isSystemDomainLoader(var0.getClassLoader())) {
        throw new SecurityException("Unsafe");
    } else {
        return theUnsafe;
    }
} // 只有主类的加载器才能获取到Unsafe的对象。

不过呢,你实在想要用,还是可以用的,大家都不难想象到反射了吧!
获取Unsafe类的实例方法如下
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessable(true);
Unsafe instance = (Unsafe)field.get(null);

获取到Unsafe类之后,你就可以做到很多java不让你去做的事情。比如内存操作、多线程的CAS操作等等,具体大家可以自己去百度看吧,毕竟我只是一个讲多线程的,不过很遗憾的一点 Unsafe类在 j9 已经被移除了(据说)。
来自群组: SpicyChicken

Tollainmear
正在找!就看到了!谢谢绿毛dalao!

第一页 上一页 下一页 最后一页