美文网首页
Java - 多线程应用举例

Java - 多线程应用举例

作者: sunboximeng | 来源:发表于2018-06-09 11:52 被阅读21次

1. 卖票

利用 Runnable 接口的实现类定义多个线程所要共同完成的任务(数据作为成员变量实现共享),继承Thread类的方法太笨重,继承了一堆用不着的东西。

public class Ticket implements Runnable {

    private int counter = 100; //100张票作为共享数据
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true) {
//          把共享数据锁住。
            lock.lock();

//            if (counter > 0) {
//
//                try {
//                    Thread.currentThread().sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//
//                System.out.println(Thread.currentThread().getName() +
//                "卖出第 " + (counter--) + " 张票");
//                lock.unlock();
//            } else {
////                这样写可能仍然有风险,释放锁之后,就有可能被打断了。
//                lock.unlock();
//                break;
//            }

//            利用finally实现break语句之后还可以执行操作!
            try {
                if (counter > 0) {

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() +
                    "卖出第 " + (counter--) + " 张票");

                } else {
                    break;
                }
            } finally {
                lock.unlock();
            }
        }
    }
}

注意:

while(true) {
    lock.lock();
    if (counter > 0) {}
}

不能修改为:

lock.lock();
while(counter > 0) {}

因为把while语句锁住了,某个线程就会一直执行下去。

客户端:

public class SellTicket {

    public static void main(String[] args) {

        Ticket ticket = new Ticket();
        Thread t1 = new Thread(ticket, "窗口1");
        Thread t2 = new Thread(ticket, "窗口2");
        t1.start();
        t2.start();

//        不想写类,就可以全部使用匿名内部类实现

    }
}

2. 抽奖

证明线程的栈是私有的,也就是run方法里面的局部变量是线程私有的。这意味着局部变量之间并不会互相干扰,没有安全问题。意识到这一点可以简化代码,增加代码的灵活性,不用写死。

弱鸡版(代码有一部分是写死的):

public class Lottery implements Runnable {

    private ArrayList<Integer> pool; //奖池
    private Random random;
    private Lock lock = new ReentrantLock();
    private ArrayList<Integer> box1; //线程1抽到的奖品
    private ArrayList<Integer> box2; //线程2抽到的奖品

    public Lottery(ArrayList<Integer> pool) {
        this.pool = pool;
        this.random = new Random();
        this.box1 = new ArrayList<>();
        this.box2 = new ArrayList<>();
    }

    @Override
    public void run() {

        while (true) {
            lock.lock();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                if (pool.size() > 0) {
                    int index = random.nextInt(pool.size());
                    int money = pool.remove(index);
//                    代码是写死的,抽奖箱换名字怎么办。
                    if (Thread.currentThread().getName().equals("抽奖箱1")) {
                        box1.add(money);
                    } else {
                        box2.add(money);
                    }

                } else {
                    if (Thread.currentThread().getName().equals("抽奖箱1")) {
                        printBox(box1);
                    } else {
                        printBox(box2);

                    }

                    break;
                }
            } finally {
                lock.unlock();
            }


        }
    }

    private static void printBox(ArrayList<Integer> box) {
        System.out.println("在此次抽奖过程中," + Thread.currentThread().getName() +
                "总共产生了" + box.size() + "个奖项,分别为:" + box);
        if (box.size() != 0) {
            System.out.println("最高奖项为:" + Collections.max(box) + "。 总计为:");
        }
    }


}

升级版:

public class Lottery implements Runnable {

    private ArrayList<Integer> pool;
    private Random random;
    private Lock lock = new ReentrantLock();


    public Lottery(ArrayList<Integer> pool) {
        this.pool = pool;
        this.random = new Random();
    }

    @Override
    public void run() {

//      局部变量为线程私有,每个线程都会在堆中创建一个自己的box
        ArrayList<Integer> box = new ArrayList<>(); 
        while (true) {

            lock.lock();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {

                if (pool.size() > 0) {
                    int index = random.nextInt(pool.size());
                    int money = pool.remove(index);
                    box.add(money);

                } else {
                    printBox(box);
                    break;
                }
            } finally {
                lock.unlock();
            }
        }
    }

    private static void printBox(ArrayList<Integer> box) {
        System.out.println("在此次抽奖过程中," + Thread.currentThread().getName() +
                "总共产生了" + box.size() + "个奖项,分别为:" + box);
        if (box.size() != 0) {
            System.out.println("最高奖项为:" + Collections.max(box) + "。 总计为:");
        }
    }


}

客户端:

public class LotteryTest {

    public static void main(String[] args) {

        ArrayList<Integer> arr = new ArrayList<>();

//      得到一个不可修改的List,无法对其进行增删操作。
        List<Integer> list = List.of(10,5,20,50,100,200,500,800,2,80,300,700);
        arr.addAll(list);

//        也可以这样批量添加
//        Integer[] arr1 = {10,5,20,50,100,200,500,800,2,80,300,700};
//        把可变参数作为数组传入
//        Collections.addAll(arr, arr1);

        Lottery lottery = new Lottery(arr);

        new Thread(lottery, "抽奖箱1").start();
        new Thread(lottery, "抽奖箱2").start();
    }
}

相关文章

网友评论

      本文标题:Java - 多线程应用举例

      本文链接:https://www.haomeiwen.com/subject/asrteftx.html