第14章 多线程(16)Swing 的线程补充+线程示例与常见解法
原创
©著作权归作者所有:来自51CTO博客作者钰娘娘ynn的原创作品,请联系作者获取转载授权,否则将追究法律责任
14.11.3 单一线程规则
基本原则:除了时间分配线程,不要再任何线程中接触Swing组件
特殊规则:
线程中可以添加、移除事件监听,然后触发时间分配线程
少量的Swing方法是安全的,如下:
JTextComponent.setText
JTextArea.insert
JTextArea.append
JTextArea.repalceRange
JComponent.repaint
JComponent.revalidate
记不住的话,还有个基本的,重绘方法是线程安全的,其他的当做不安全使用事件监听触发就可以了,不行就查查源码确定一下
补充1:示例:交替打印
题目来源:https://leetcode.cn/problems/print-foobar-alternately/
1115. 交替打印 FooBar
给你一个类:
class FooBar {
public void foo() {
for (int i = 0; i < n; i++) {
print("foo");
}
}
public void bar() {
for (int i = 0; i < n; i++) {
print("bar");
}
}
}
两个不同的线程将会共用一个 FooBar 实例:
请设计修改程序,以确保 "foobar" 被输出 n 次。
示例 1:
输入:n = 1
输出:"foobar"
解释:这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。
示例 2:
输入:n = 2
输出:"foobarfoobar"
解释:"foobar" 将被输出两次。
提示:
- 1 <= n <= 1000
- 线程 A 将会调用 foo() 方法,而
- 线程 B 将会调用 bar() 方法
以下给出三种解法(都是自己写):
解法一:使用锁+Condition
💐 加解锁
💐 如果不满足,阻塞 wait()
💐 满足处理后,signalAll()
class FooBar {
private int n;
private ReentrantLock lock;
private Condition c;
private volatile boolean used;
public FooBar(int n) {
this.n = n;
lock = new ReentrantLock();
c = lock.newCondition();
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
if(used) c.await();
// printFoo.run() outputs "foo". Do not change or remove this line.
printFoo.run();
used = true;
c.signalAll();
lock.unlock();
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
if(!used) c.await();
// printBar.run() outputs "bar". Do not change or remove this line.
printBar.run();
used = false;
c.signalAll();
lock.unlock();
}
}
}
解法二:使用synchronized+wait+notify
💐 Synchronized 方法或代码块
💐 不满足条件wait阻塞
💐 满足处理后notifyAll
class FooBar {
private int n;
private volatile boolean isFoo = true;
public FooBar(int n) {
this.n = n;
}
public synchronized void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
if(!isFoo)
this.wait();
// printFoo.run() outputs "foo". Do not change or remove this line.
printFoo.run();
isFoo = false;
this.notifyAll();
}
}
public synchronized void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
if(isFoo)
this.wait();
// printBar.run() outputs "bar". Do not change or remove this line.
printBar.run();
isFoo = true;
this.notifyAll();
}
}
}
解法三:使用 Semaphore
💐 几种信号建立不同的信号量(通常开始元素确定,一个有通行证,其他没有;不确定则大家都分配通行证)
💐 第一种信号处理完,给第二种信号量
💐 第二种信号处理完,给第一种信号量
class FooBar {
private int n;
private Semaphore semaphore1 = new Semaphore(1);
private Semaphore semaphore2 = new Semaphore(0);
public FooBar(int n) {
this.n = n;
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
semaphore1.acquire();
// printFoo.run() outputs "foo". Do not change or remove this line.
printFoo.run();
semaphore2.release();
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
semaphore2.acquire();
// printBar.run() outputs "bar". Do not change or remove this line.
printBar.run();
semaphore1.release();
}
}
}
本来还想给第二个例子,写了几题都差不多,思路都是 Semaphore/lock+Condition/synchronized+wait+notifyAll
从下一节开始写补充的知识点:
💐 线程的生命周期
💐 创建线程的三种方式
💐 线程中常用锁:互斥锁、条件锁、自旋锁、读写锁、乐观锁、悲观锁、公平锁、非公平锁
相关内容:选择 《Java核心技术 卷1》查找相关笔记
评论🌹点赞👍收藏✨关注👀,是送给作者最好的礼物,愿我们共同学习,一起进步
公众号 钰娘娘知识汇总