内容学习于:edu.aliyun.com


1. 数字加减

  设计4个线程对象,两个线程执行减操作,两个线程执行加操作。

代码:

class AddThread implements Runnable {
    private Resource resource;

    public AddThread(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                this.resource.add();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class SubThread implements Runnable {
    private Resource resource;

    public SubThread(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                this.resource.sub();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


class Resource {//定义操作的资源
    private volatile int num = 0;//被进行操作的数据
    private boolean flag = true;//表示允许的操作
    //flag = true,表示允许加法,不允许减法
    //flag = flase,表示允许减法,不允许加法

    public synchronized void add() throws InterruptedException {//同步加法操作
        if (this.flag == false) {//如果不允许加法,则该线程等待
            super.wait();
        }
        Thread.sleep(100);
        this.num++;
        System.out.println("【加法操作-" + Thread.currentThread().getName() + "】" + "num=" + this.num);
        this.flag = false;//执行完加法,将允许减法不允许加法
        super.notifyAll();//唤醒所有等待线程
    }

    public synchronized void sub() throws InterruptedException {//同步减法操作
        if (this.flag == true) {//如果不允许减法,则该线程等待
            super.wait();
        }
        Thread.sleep(200);
        this.num--;
        System.out.println("【减法操作-" + Thread.currentThread().getName() + "】" + "num=" + this.num);
        this.flag = true;//执行完减法,将允许加法不允许减法
        super.notifyAll();//唤醒所有等待线程
    }

}

public class ThreadDemo {
    public static void main(String[] args) {
        Resource resource = new Resource();
        AddThread at = new AddThread(resource);
        SubThread st = new SubThread(resource);
        new Thread(at, "加法线程-A").start();
        new Thread(at, "加法线程-B").start();
        new Thread(st, "减法线程-X").start();
        new Thread(st, "减法线程-Y").start();
    }
}

结果:

【加法操作-加法线程-A】num=1
【减法操作-减法线程-X】num=0
【加法操作-加法线程-B】num=1
【减法操作-减法线程-X】num=0
【加法操作-加法线程-B】num=1
【减法操作-减法线程-X】num=0
【加法操作-加法线程-B】num=1
【减法操作-减法线程-X】num=0
【加法操作-加法线程-B】num=1
【减法操作-减法线程-X】num=0
【加法操作-加法线程-B】num=1
【减法操作-减法线程-Y】num=0
【加法操作-加法线程-A】num=1
【减法操作-减法线程-Y】num=0
【加法操作-加法线程-A】num=1
【减法操作-减法线程-Y】num=0
【加法操作-加法线程-A】num=1
【减法操作-减法线程-Y】num=0
【加法操作-加法线程-A】num=1
【减法操作-减法线程-Y】num=0

  这一题目是一个经典的多线程的开发操作,这一个程序里面一定要考虑的核心本质在于:加一个、减一个,<mark>整体的计算结果应该只在0、-1、1之间循环出现。</mark>

2. 生产电脑

  设计一个生产电脑和搬运电脑类,要求生产出一台电脑就搬走一台电脑,如果没有新的电脑生产出来,则搬运工要等待新电脑产出;如果生产出的电脑没有搬走,则要等待电脑搬走之后再生产,并统计出生产的电脑数量。在本程序之中实现的就是一个标准的生产者与消费者的处理模型,那么下面实现具体的程序代码。

代码:

class Producer implements Runnable {//生产者线程
    private Resource resource;

    public Producer(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                this.resource.make();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Customer implements Runnable {//生产者线程
    private Resource resource;

    public Customer(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                this.resource.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Computer {
    private static int count;
    private String name;
    private double price;

    public Computer(String name, double price) {
        this.name = name;
        this.price = price;
        count++;
    }

    @Override
    public String toString() {
        return "【第" + count + "台电脑】" + "、电脑名字:" + this.name + "、电脑价格:" + this.price;
    }
}

class Resource {
    private Computer computer;

    public synchronized void make() throws InterruptedException {
        if (this.computer != null) {//已经生产过了
            super.wait();
        }
        Thread.sleep(100);
        this.computer = new Computer("Xzzz", 2020.0);
        System.out.println("【生产电脑】" + this.computer);
        super.notifyAll();
    }

    public synchronized void get() throws InterruptedException {
        if (computer == null) {//还未生产
            super.wait();
        }
        Thread.sleep(10);
        System.out.println("【取走电脑】" + this.computer);
        this.computer = null;//电脑已经被消费走
        super.notifyAll();
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        Resource resource = new Resource();
        new Thread(new Producer(resource)).start();
        new Thread(new Customer(resource)).start();
    }
}

结果:

【生产电脑】【第1台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【取走电脑】【第1台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【生产电脑】【第2台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【取走电脑】【第2台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【生产电脑】【第3台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【取走电脑】【第3台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【生产电脑】【第4台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【取走电脑】【第4台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【生产电脑】【第5台电脑】、电脑名字:Xzzz、电脑价格:2020.0
【取走电脑】【第5台电脑】、电脑名字:Xzzz、电脑价格:2020.0

3. 竞争抢答

  实现一个竞拍抢答程序:要求设置三个抢答者(三个线程),而后同时发出抢答指令,抢答成功者给出成功提示,未抢答成功者给出失败提示。
  <mark>对于这一个多线程的操作由于里面需要牵扯到数据的返回问题,那么现在最好使用的Callable是比较方便的一种处理形式。</mark>

代码:

class MyThread implements Callable<String> {
    private boolean flag = false;//抢答处理

    @Override
    public String call() throws Exception {
        synchronized (this) {
            if (flag == false) {//抢答成功
                Thread.sleep(100);
                this.flag = true;
                return Thread.currentThread().getName() + "强答成功";
            } else {
                return Thread.currentThread().getName() + "强答失败";
            }
        }

    }
}

public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread mt = new MyThread();
        FutureTask<String> taskA = new FutureTask<>(mt);
        FutureTask<String> taskB = new FutureTask<>(mt);
        FutureTask<String> taskC = new FutureTask<>(mt);
        new Thread(taskA, "竞赛者A").start();
        new Thread(taskB, "竞赛者B").start();
        new Thread(taskC, "竞赛者C").start();
        System.out.println(taskA.get());
        System.out.println(taskB.get());
        System.out.println(taskC.get());
    }
}

结果:

竞赛者A强答失败
竞赛者B强答成功
竞赛者C强答失败