第14章 多线程(16)Swing 的线程补充+线程示例与常见解法_java

第14章 多线程(16)Swing 的线程补充+线程示例与常见解法_i++_02

 14.11.3 单一线程规则

基本原则:除了时间分配线程,不要再任何线程中接触Swing组件

特殊规则:

线程中可以添加、移除事件监听,然后触发时间分配线程

少量的Swing方法是安全的,如下:

JTextComponent.setText

JTextArea.insert

JTextArea.append

JTextArea.repalceRange

JComponent.repaint

JComponent.revalidate

记不住的话,还有个基本的,重绘方法是线程安全的,其他的当做不安全使用事件监听触发就可以了,不行就查查源码确定一下

第14章 多线程(16)Swing 的线程补充+线程示例与常见解法_idea_03

 补充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》查找相关笔记

评论🌹点赞👍收藏✨关注👀,是送给作者最好的礼物,愿我们共同学习,一起进步

公众号 钰娘娘知识汇总 

第14章 多线程(16)Swing 的线程补充+线程示例与常见解法_信号量_04