Java作业-11

线程相关

使用线程池的好处是什么?

  • 资源管理:线程池有效管理线程的创建和销毁。创建线程是一个昂贵的操作,线程池通过重用已存在的线程减少了这个开销。
  • 性能提升:因为减少了每次任务执行时线程创建和销毁的开销,线程池能显著提升系统性能。
  • 稳定性和可靠性:线程池可以限制系统中线程的最大数量,避免了过多线程导致的内存消耗过大和切换开销,从而增加了系统的稳定性。
  • 更好的任务管理:线程池提供了一种管理任务队列的方式。可以根据需求控制任务的执行顺序(比如先进先出、优先级)。
  • 提供更多的控制:线程池允许用户自定义线程池的大小、线程的创建方式、线程的优先级等,提供了更灵活的线程管理方式。
  • 负载均衡:线程池可以根据系统的负载情况动态调整线程的数量,从而实现负载均衡。
  • 减少资源竞争:由于线程数量得到控制和管理,线程间的资源竞争也会减少,这有助于系统资源的有效利用。

如何创建一个锁对象,如何得到一个锁和释放一个锁?

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

Lock lock = new ReentrantLock();

lock.lock();
try {
    // 访问或修改共享资源
} finally {
    lock.unlock();
}
  • 确保释放锁:始终在finally块中释放锁,确保无论代码执行过程中发生什么,锁都会被释放。
  • 避免死锁:确保在持有一个锁的同时不要去获取另一个锁,这可能会导致死锁。
  • 锁的选择:ReentrantLock是一个可重入锁,它允许线程多次获取同一个锁。根据具体需求选择合适的锁类型。

如何创建锁的条件?方法await()、signal()、signalAll()的用途分别是什么?

方法 接口 用途
lock() Lock 获取锁。如果锁不可用,则当前线程将被禁用以用于线程调度目的并处于休眠状态,直到获得锁。
unlock() Lock 释放锁。
newCondition() Lock 返回绑定到此Lock实例的新Condition实例。
await() Condition 使当前线程等待,直到被signal()或signalAll()唤醒,或者被中断。
signal() Condition 唤醒一个等待在Condition上的线程。
signalAll() Condition 唤醒所有等待在Condition上的线程。

如果将30-6中56行的while改为if,会发生什么?

题目:while(balance < amount)替换为 if(balance < amount)
可能取出多于存款数目的钱

下面代码有什么错误

synchronized(object1){
    try{
        while(!condition) object2.wait();
    }catch (InterruptedException ex){

    }
}
  1. 使用错误的对象调用wait():在Java中,调用wait()方法应该在持有该对象的监视器锁时进行。代码中在object1的监视器锁内调用的object2.wait()。这意味着应该在object2的同步块中调用wait()方法,除非object1和object2是同一个对象。
  2. 未处理中断异常:当线程被中断时,InterruptedException会被抛出。通常,这个异常应该被适当处理,而不是被空捕获。一个常见的做法是在捕获块中至少恢复中断状态:
catch (InterruptedException ex) {
    Thread.currentThread().interrupt(); // 恢复中断状态
    // 可以选择在这里处理中断
}
  1. 潜在的死锁:如果object1和object2是不同的对象,那么这种在不同对象上同步的方式可能会导致死锁,特别是如果其他线程也在尝试以相反的顺序锁定这些对象。

改写程序清单30-1,在文本域中显示出输出结果

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;

public class MainClass {
    private static final Print print = new Print();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        executorService.execute(new PrintChar('a', 100));
        executorService.execute(new PrintChar('b', 100));
        executorService.execute(new PrintNum(99));
        executorService.shutdown();
    }

    static class Print {
        private static final Lock lock = new ReentrantLock();
        private static final Condition printCondition = lock.newCondition();
        private Integer num = 0;

        public void setNum(Integer num) {
            this.num = num;
        }

        public void printNum() {
            lock.lock();
            try {
                System.out.print(num + " ");
                printCondition.signalAll();
            } catch (Exception e) {
                // 异常处理逻辑
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void printChar(Character c) {
            lock.lock();
            try {
                while (num >= 10 && num < 99) {
                    printCondition.await();
                }
                System.out.print(c);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }

    static class PrintChar implements Runnable {
        private final char charToPrint;
        private final int times;

        public PrintChar(char c, int t) {
            charToPrint = c;
            times = t;
        }

        public void run() {
            for (int i = 0; i < times; i++) {
                print.printChar(charToPrint);
            }
        }
    }

    static class PrintNum implements Runnable {
        private final int lastNum;

        public PrintNum(int n) {
            lastNum = n;
        }

        public void run() {
            for (int i = 1; i <= lastNum; i++) {
                print.setNum(i);
                print.printNum();
            }
        }
    }
}
// 输出
aaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 aaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

(同步线程)编写一个程序,启动 1000 个线程。每个线程给初始值为0的变量 sum加1。定义一个Integer 包装对象来保存 sum。使用同步和不使用同步来运行这个程序,看一看它们的效果

public class NonSynchronizedCounter {
    private Integer sum = 0;

    public void increment() {
        sum++;
    }

    public Integer getSum() {
        return sum;
    }

    public static void main(String[] args) throws InterruptedException {
        NonSynchronizedCounter counter = new NonSynchronizedCounter();
        Thread[] threads = new Thread[1000];

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> counter.increment());
            threads[i].start();
        }

        for (Thread thread : threads) {
            thread.join();
        }

        System.out.println("Final sum (Non-Synchronized): " + counter.getSum());
    }
}


public class SynchronizedCounter {
    private Integer sum = 0;

    public synchronized void increment() {
        sum++;
    }

    public Integer getSum() {
        return sum;
    }

    public static void main(String[] args) throws InterruptedException {
        SynchronizedCounter counter = new SynchronizedCounter();
        Thread[] threads = new Thread[1000];

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> counter.increment());
            threads[i].start();
        }

        for (Thread thread : threads) {
            thread.join();
        }

        System.out.println("Final sum (Synchronized): " + counter.getSum());
    }
}

使用控制风扇动画的线程改写编程练习题15.28

private static final Double MIN_WIDTH = 320.0;
private static final Double MIN_HEIGHT = 200.0;
@Override
public void start(Stage stage) {
    Pane pane = new Pane();
    VBox fanAndControl = new VBox(50);
    fanAndControl.setMinWidth(MIN_WIDTH);
    fanAndControl.setMinHeight(MIN_HEIGHT);
    fanAndControl.setAlignment(Pos.TOP_CENTER);
    HBox fanBox = new HBox();
    fanBox.setAlignment(Pos.CENTER);
    Pane fanPane = new Pane();
    Circle circle = new Circle(60, 60, 60);
    circle.setStroke(Color.BLACK);
    circle.setFill(Color.WHITE);
    fanPane.getChildren().add(circle);
    Group group = new Group();
    // 构建运动弧
    for (int i = 0; i < 4; i++) {
        Arc moveArc = new Arc(60, 60, 50, 50, 30 + i * 90, Math.PI * 25 / 3);
        moveArc.setType(ArcType.ROUND);
        moveArc.setFill(Color.BLACK);
        group.getChildren().add(moveArc);
    }
    fanPane.getChildren().add(group);
    fanBox.getChildren().add(fanPane);
    HBox controlBox = new HBox(20);
    controlBox.setAlignment(Pos.CENTER);
    // 风扇默认方向为逆时针,用布尔数组规避lambda无法修改外部变量的问题
    Lock lock = new ReentrantLock();
    Boolean[] isActive = {true};
    Boolean[] isPause = {false};
    Runnable rotateThread = () -> {
        lock.lock();
        try {
            while (!isPause[0]) {
                if (isActive[0]) {
                    group.setRotate(group.getRotate() + 1);
                } else {
                    group.setRotate(group.getRotate() - 1);
                }
                Thread.sleep(1);
            }
        } catch (Exception e) {
        } finally {
            lock.unlock();
        }
    };
    new Thread(rotateThread).start();
    Button pauseBtn = new Button("Pause");
    pauseBtn.setOnAction(e ->
    {
        isPause[0] = true;
    });
    Button resumeBtn = new Button("Resume");
    resumeBtn.setOnAction(e -> {
        if (isPause[0]) {
            isPause[0] = false;
            new Thread(rotateThread).start();
        }
    });
    Button reverseBtn = new Button("Reverse");
    reverseBtn.setOnAction(e -> {
        isActive[0] = !isActive[0];
    });
    controlBox.getChildren().addAll(pauseBtn, resumeBtn, reverseBtn);
    fanAndControl.getChildren().addAll(fanBox, controlBox);
    pane.getChildren().addAll(fanAndControl);
    Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.show();
}

使用对象的wait()和notifyAll()方法改写程序清单30-6

private static class Account {
    private int balance = 0;

    public int getBalance() {
        return balance;
    }

    public void withdraw(int amount) {
        synchronized (account) {
            try {
                while (balance < amount) {
                    System.out.println("\t\t\tWait for a deposit");
                    this.wait();
                }
                balance -= amount;
                System.out.println("\t\t\tWithdraw " + amount +
                        "\t\t" + getBalance());
                
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void deposit(int amount) {
        synchronized (account) {
            try {
                balance += amount;
                System.out.println("Deposit " + amount +
                        "\t\t\t\t\t" + getBalance());
            } finally {
                this.notifyAll();
            }
        }
    }
}