A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 董将 中级黑马   /  2012-12-7 23:44  /  1106 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

同步的好处:
                解决了多线程的安全问题。
       
        同步的弊端:
                1,相对消耗资源。
                2,容易出现死锁。(当这个同步嵌套的时候容易出现,大家在开发时,尽量避免。)

        为了面试:
               
        //定义锁类。
        class MyLock
        {
                static MyLock locka = new MyLock();
                static MyLock lockb = new MyLock();
        }

        class Demo implements Runnable
        {
                private boolean flag ;
                Demo(boolean flag)
                {
                        this.flag = flag;
                }
                public void run()
                {
                        if(flag)
                        {
                                while(true)
                                {
                                        synchronized(MyLock.locka)
                                        {
                                                System.out.println("if......locka");
                                                synchronized(MyLock.lockb)
                                                {
                                                        System.out.println("if......lockb");
                                                       
                                                }
                                        }
                                }
                        }
                        else
                        {
                                while(true)
                                {
                                        synchronized(MyLock.lockb)
                                        {
                                                System.out.println("else......lockb");
                                                synchronized(MyLock.locka)
                                                {
                                                        System.out.println("else......locka");
                                                       
                                                }
                                        }
                                }
                        }
                }
        }

        class DeadLockDemo
        {
                public static void main(String[] args)
                {
                        Demo d1 = new Demo(true);
                        Demo d2 = new Demo(false);

                        new Thread(d1).start();
                        new Thread(d2).start();
                }
        }
       

        -----------------------------------

        线程间通信。
        多个线程在处理同一个数据资源,但是处理的动作却不一致。
        这里就用到一个机制  等待/唤醒 机制。

        等待和唤醒:
        wait():让线程处于等待状态。这时线程会释放锁。并存入到了线程池中。
        notify():通常唤醒线程池中的第一个。
        notifyAll():将线程池中的所有等待线程都唤醒。

        这三个方法都需要定义在同步当中。因为要标识出它们所作用的锁。
        如果用在同步外,有可能发生 无效线程状态异常。
        三个方法为什么定义在Object类中?因为锁可以任意对象,被任意对象都能调用的方法肯定定义在Object类。
       
        //需求:两个线程对同一个资源进行操作,一个赋值姓名和性别,一个线程负责打印姓名和性别。
        //1,定义资源。
        class Res
        {
                private String name;
                private String sex;
                private boolean flag = false;
                public synchronized  void set(String name,String sex)
                {
                        if(flag)
                                try{this.wait();}catch(InterruptedException e){}                       
                        this.name = name;
                        this.sex = sex;
                        flag = true;
                        this.notify();
                }

                public synchronized void out()
                {
                        if(!flag)
                                try{this.wait();}catch(InterruptedException e){}
                        System.out.println(name+"..."+sex);
                        flag = false;
                        this.notify();
                }
        }
       
        class Input implements Runnable
        {
                private Res r;
                Input(Res r)
                {
                        this.r = r;
                }
                public void run()
                {
                        int x = 0;
                        while(true)
                        {
                                if(x==0)
                                {
                                        r.set("mike","nan");
                                }
                                else
                                        r.set("丽丽","女女");
                                x = (x+1)%2;
                        }
                }
        }

        class Output implements Runnable
        {
                private Res r;
                Output(Res r)
                {
                        this.r = r;
                }
                public void run()
                {
                        while(true)
                        {
                                r.out();
                        }
                }
        }

        class ResDemo
        {
                public static void main(String[] args)
                {
                        Res r = new Res();

                        new Thread(new Input(r)).start();
                        new Thread(new Output(r)).start();
                }
        }

        wait()和sleep()的特点:
        wait:可以有时间限定,也可以没有时间限定。
        sleep:必须有时间限定。

        wait:释放cpu执行资源,也释放锁。
        sleep:释放cpu执行资源,不释放锁。
        ----------------------------------------

        线程间通信的演化。
        需求:
        当多个线程进行通信时,一部分线程在进行存储动作,一部分线程在进行取出动作。
        无论多少个线程进行存储,只有可以可以执行,无论多少个线程进行取出,只能取出一次。
       
        class Res
        {
                private String name;
                private boolean flag;
                private int count = 0;

                public synchronized void set(String name)throws InterruptedException
                {
                        while(flag)
                                wait();
                        this.name = name;
                        add();
                        System.out.println(Thread.currentThread().getName()+"----生产----"+name+"::"+count);
                        flag = true;
                        notifyAll();

                }
                public synchronized void out()throws InterruptedException
                {
                        while(!flag)
                                wait();
                        System.out.println(Thread.currentThread().getName()+"....消费...."+name+"::"+count);
                        flag = false;
                        notifyAll();
                }
                public void add()
                {
                        count++;
                }
        }

        class Input implements Runnable
        {
                private Res r;
                Input(Res r)
                {
                        this.r = r;
                }
                public void run()
                {
                        while(true)
                        {
                                try{r.set("商品");}catch(InterruptedException e){}
                        }
                }
        }
        class Output implements Runnable
        {
                private Res r;
                Output(Res r)
                {
                        this.r = r;
                }
                public void run()
                {
                        while(true)
                        {
                                try{r.out();}catch(InterruptedException e){}
                        }
                }
        }

        class ResDemo
        {
                public static void main(String[] args)
                {
                        Res r = new Res();

                        //创建两个生成者
                        new Thread(new Input(r)).start();
                        new Thread(new Input(r)).start();
                        //创建两个消费者
                        new Thread(new Output(r)).start();
                        new Thread(new Output(r)).start();
                }
        }

        发现结果不爽!要么就生产不断的生产,却没有被消费,要么就是消费者不断的消费,却没有生产。
        当然在某一时段,也会出现和谐情况。多运行就会不和谐。

        发生的原因的是:当线程等待时。再次被唤醒,不会在去判断标记flag。
        那么就会发生数据错乱的情况。

        解决办法:一定要醒来的线程再一次判断标记。所以要将判断的标记的if改成while。
        这时就将if(flag)改成while(flag).

        该完以后,发现,郁闷了,线程和不和谐不重要,程序虽然没有结束,但是生产者消费者都不再运行,
        因为都处于wait状态。

        原因:是出现循环判断后,线程每一次都判断标记,都会出现等待的情况,
        例如:3个线程等待,第四个线程,唤醒了其中一个,而这一个也是和该线程属于同一方的。

        解决:希望可以唤醒另一放的线程。比如:消费需要去唤醒生产的。
        而在Object提供的监视器方法中只提供了notify,和notifyAll进行唤醒。
        所以这时可以使用notifyAll,将所有等待的线程都唤醒,这些线程中就包括对方线程。

        就需要将代码中的notify改成notifyAll。

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马