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){
}
}
- 使用错误的对象调用wait():在Java中,调用wait()方法应该在持有该对象的监视器锁时进行。代码中在object1的监视器锁内调用的object2.wait()。这意味着应该在object2的同步块中调用wait()方法,除非object1和object2是同一个对象。
- 未处理中断异常:当线程被中断时,InterruptedException会被抛出。通常,这个异常应该被适当处理,而不是被空捕获。一个常见的做法是在捕获块中至少恢复中断状态:
catch (InterruptedException ex) {
Thread.currentThread().interrupt(); // 恢复中断状态
// 可以选择在这里处理中断
}
- 潜在的死锁:如果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();
}
}
}
}