线程之间的联系
本文最后更新于70 天前,其中的信息可能已经过时,如有错误请发送邮件到434658198@qq.com

1、下面程序会有什么问题

package examination;

import java.util.ArrayList;
import java.util.List;

/**
 * taobao examination
 * 实现一个容器,提供两个方法,add和size
 * 写两个线程,线程1添加10个元素到容器中,
 * 线程2实现监控元素的个数,当个数到5个时,
 * 线程2给出提示并结束
 * @author xzq
 */
public class Examination01 {

    public static void main(String[] args) {
        final Box_1 box=new Box_1();

        new Thread("线程1"){

            @Override
            public void run() {
                try {
                    for(int i=1;i<=10;i++){
                        box.add(new Object());
                        System.out.println("线程1:add第"+i+"个元素");
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();


        new Thread("线程2"){

            @Override
            public void run() {
                while(true){
                    if(box.size()==5){
                        break;
                    }
                }
                System.out.println("线程2执行完毕!");
            }
        }.start();
    }

}

/**
 * 这样实现有什么问题?
 * @author xzq
 */
class Box_1{

    private List<Object> box=new ArrayList<>();

    public void add(Object element){
        box.add(element);
    }

    public int size(){
        return box.size();
    }

}

线程2不会得到通知,不会结束

2、解决问题 为对象添加volatile

private volatile List box=new ArrayList<>();

package examination;


import java.util.ArrayList;
import java.util.List;

/**
 * taobao examination
 * 实现一个容器,提供两个方法,add和size
 * 写两个线程,线程1添加10个元素到容器中,
 * 线程2实现监控元素的个数,当个数到5个时,
 * 线程2给出提示并结束
 * @author xzq
 */
public class Examination02 {

    public static void main(String[] args) {
        final Box_2 box=new Box_2();

        new Thread("线程1"){

            @Override
            public void run() {
                try {
                    for(int i=1;i<=10;i++){
                        box.add(new Object());
                        System.out.println("线程1:add第"+i+"个元素");
                        Thread.sleep(1_000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();


        new Thread("线程2"){

            @Override
            public void run() {
                try {
                    while(true){
                        if(box.size()==5){
                            Thread.sleep(2_000);
                            System.out.println("线程2:我看到容器中已经有5个元素啦!!!");
                            break;
                        }
                    }
                    System.out.println("线程2:执行完毕!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

}

/**
 * 加上volatile使box的修改可以得到通知
 * 这样实现有什么问题?
 *
 * 1、由于add和size没有加锁,那么就不具备互斥性,
 * 有可能会出现当线程2判断完size==5后,线程切换了
 * 然后线程1又加了一次已经到6了,然后在切换回线程2
 * 此时,线程2才break,这样就与原逻辑不符。
 *
 * 2、用死循环的方式十分浪费CPU的资源
 * @author xzq
 */
class Box_2{

    private volatile List<Object> box=new ArrayList<>();

    public void add(Object element){
        box.add(element);
    }

    public int size(){
        return box.size();
    }

}

3、使用wait和notify方法

package examination;

import java.util.ArrayList;
import java.util.List;

/**
 * taobao examination
 * 实现一个容器,提供两个方法,add和size
 * 写两个线程,线程1添加10个元素到容器中,
 * 线程2实现监控元素的个数,当个数到5个时,
 * 线程2给出提示并结束
 *
 * 这里使用wait()和notify()方法实现,
 * 注意:wait()会释放锁,而nodify()不会释放锁。
 *
 * 该例中线程2必须比线程1先启动,才能保持监听状态
 * 因为必须先wait,才有nodify。
 *
 * 但是本程序的输出还是没有达到预期效果:
 * size=5的时候线程2没有继续往下执行,而是
 * 等到线程1执行完毕后才往下执行的,因为
 * nodify是不释放锁的,而wait被nodify后是需要
 * 重新持有锁的,但是现在这把锁被线程1持有着
 * 所以只能等到线程1离开同步代码块时,线程2
 * 才能继续往下执行。

 * @author xzq
 */
public class Examination03 {

    public static void main(String[] args) {
        final Box_3 box=new Box_3();
        final Object obj=new Object();

        new Thread("线程2"){

            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        System.out.println("线程2:开始执行");
                        if(box.size()!=5){
                            obj.wait();
                        }
                        System.out.println("线程2:执行完毕!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();



        new Thread("线程1"){

            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        System.out.println("线程1:开始执行");
                        for(int i=1;i<=10;i++){
                            box.add(new Object());
                            System.out.println("线程1:add第"+i+"个元素");
                            if(box.size()==5){
                                obj.notify();
                            }
                            Thread.sleep(1_000);
                        }
                        System.out.println("线程1:执行完毕!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

}

/**
 * 加上volatile后使box的修改可以得到通知
 *
 * @author Peter
 */
class Box_3{

    private volatile List<Object> box=new ArrayList<>();

    public void add(Object element){
        box.add(element);
    }

    public int size(){
        return box.size();
    }

}

4、优化wait和notify方法

package examination;

import java.util.ArrayList;
import java.util.List;

/**
 * taobao examination
 * 实现一个容器,提供两个方法,add和size
 * 写两个线程,线程1添加10个元素到容器中,
 * 线程2实现监控元素的个数,当个数到5个时,
 * 线程2给出提示并结束
 *
 * 这里使用wait()和notify()方法实现,
 * 注意:wait()会释放锁,而nodify()不会释放锁。
 *
 * 该例中线程2必须比线程1先启动,才能保持监听状态
 * 因为必须先wait,才有nodify。
 *
 * 但是本程序的输出还是没有达到预期效果:
 * size=5的时候线程2没有继续往下执行,而是
 * 等到线程1执行完毕后才往下执行的,因为
 * nodify是不释放锁的,而wait被nodify后是需要
 * 重新持有锁的,但是现在这把锁被线程1持有着
 * 所以只能等到线程1离开同步代码块时,线程2
 * 才能继续往下执行。
 *
 * 解决方案:
 * 线程1在nodify后必须要释放锁,那么就得wait了,
 * 然后线程2被唤醒后也必须再nodify通知线程2。
 * @author xzq
 */
public class Examination04 {

    public static void main(String[] args) {
        final Box_4 box=new Box_4();
        final Object obj=new Object();

        new Thread("线程2"){

            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        System.out.println("线程2:开始执行");
                        if(box.size()!=5){
                            obj.wait();
                        }
                        System.out.println("线程2:执行完毕!");
                        //通知线程2我已经被唤醒了,你也别等着了
                        obj.notify();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();



        new Thread("线程1"){

            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        System.out.println("线程1:开始执行");
                        for(int i=1;i<=10;i++){
                            box.add(new Object());
                            System.out.println("线程1:add第"+i+"个元素");
                            if(box.size()==5){
                                obj.notify();
                                //释放锁,让线程2得以执行。
                                obj.wait();
                            }
                            Thread.sleep(1_000);
                        }
                        System.out.println("线程1:执行完毕!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

}

/**
 * 加上volatile后使box的修改可以得到通知
 *
 * @author xzq
 */
class Box_4{

    private volatile List<Object> box=new ArrayList<>();

    public void add(Object element){
        box.add(element);
    }

    public int size(){
        return box.size();
    }

}

5、使用CyclicBarrier方法解决

package examination;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * taobao examination
 * 实现一个容器,提供两个方法,add和size
 * 写两个线程,线程1添加10个元素到容器中,
 * 线程2实现监控元素的个数,当个数到5个时,
 * 线程2给出提示并结束
 *
 * 这里使用CountDownLatch/CyclicBarrier/Semaphore
 * 都可以简便解决这个需求
 * @author xzq
 */
public class Examination05 {


    public static void main(String[] args) {
        final Box_5 box=new Box_5();

        final CyclicBarrier barrier=new CyclicBarrier(2);

        new Thread("线程2"){

            @Override
            public void run() {
                try {
                    System.out.println("线程2:开始执行");
                    if(box.size()!=5){
                        barrier.await();
                    }
                    System.out.println("线程2:执行完毕!");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }.start();



        new Thread("线程1"){

            @Override
            public void run() {
                try {
                    System.out.println("线程1:开始执行");
                    for(int i=1;i<=10;i++){
                        box.add(new Object());
                        System.out.println("线程1:add第"+i+"个元素");
                        if(box.size()==5){
                            barrier.await();
                        }
                        Thread.sleep(1_000);
                    }
                    System.out.println("线程1:执行完毕!");
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

}

/**
 * 加上volatile后使box的修改可以得到通知
 *
 * @author xzq
 */
class Box_5{

    private volatile List<Object> box=new ArrayList<>();

    public void add(Object element){
        box.add(element);
    }

    public int size(){
        return box.size();
    }

}

6、使用Semaphore 信号灯方法

package examination;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;

/**
 *  taobao examination
 * 实现一个容器,提供两个方法,add和size
 * 写两个线程,线程1添加10个元素到容器中,
 * 线程2实现监控元素的个数,当个数到5个时,
 * 线程2给出提示并结束
 *
 * 这里使用CountDownLatch/CyclicBarrier/Semaphore
 * 都可以简便解决这个需求
 * @author xzq
 */
public class Examination06 {


    public static void main(String[] args) {
        final Box_6 box=new Box_6();

        final Semaphore reachSema=new Semaphore(0);


//      final Semaphore addSema=new Semaphore(10);

        final Semaphore addSema=new Semaphore(1);


        new Thread("线程2"){

            @Override
            public void run() {
                try {
                    System.out.println("线程2:开始执行");
                    if(box.size()!=5){
                        reachSema.acquire();
                    }
                    System.out.println("线程2:执行完毕!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();




        new Thread("线程1"){

            @Override
            public void run() {
                try {
                    System.out.println("线程1:开始执行");
                    for(int i=1;i<=10;i++){
                        addSema.acquire();
                        box.add(new Object());
                        System.out.println("线程1:add第"+i+"个元素");
                        if(box.size()==5){
                            reachSema.release();
                        }
                        addSema.release();
                        Thread.sleep(1_000);
                    }
//                      addSema.release();//这里是创建10个信号灯的实现
                    System.out.println("线程1:执行完毕!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }

}

/**
 * 加上volatile后使box的修改可以得到通知
 *
 * @author xzq
 */
class Box_6{

    private volatile List<Object> box=new ArrayList<>();

    public void add(Object element){
        box.add(element);
    }

    public int size(){
        return box.size();
    }

}
如果觉得本文对您有所帮助,可以支持下博主,一分也是缘
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇