首页 > 编程语言 >Java 多线程编程 力扣实题

Java 多线程编程 力扣实题

时间:2024-05-25 16:45:15浏览次数:25  
标签:实题 调用 void 力扣 second 线程 多线程 public first

多线程编程实例

了解内存模型、线程通信和线程安全之后,对多线程编程已经有了理论上的认知,现在来实战一下。所有题目在https://leetcode.cn/problemset/concurrency/。

按序打印

题干描述

给你一个类:

public class Foo {

public void first() { print("first"); }

public void second() { print("second"); }

public void third() { print("third"); }

}

三个不同的线程 A、B、C 将会共用一个 Foo 实例。

  • 线程 A 将会调用 first() 方法
  • 线程 B 将会调用 second() 方法
  • 线程 C 将会调用 third() 方法

请设计修改程序,以确保 second() 方法在 first() 方法之后被执行,third() 方法在 second() 方法之后被执行。

提示:

  • 尽管输入中的数字似乎暗示了顺序,但是我们并不保证线程在操作系统中的调度顺序。
  • 你看到的输入格式主要是为了确保测试的全面性。

示例 1:

输入: nums = [1,2,3]
输出: "firstsecondthird"
解释:
有三个线程会被异步启动。输入 [1,2,3] 表示线程 A 将会调用 first() 方法,线程 B 将会调用 second() 方法,线程 C 将会调用 third() 方法。正确的输出是 "firstsecondthird"。

示例 2:

输入: nums = [1,3,2]
输出: "firstsecondthird"
解释:
输入 [1,3,2] 表示线程 A 将会调用 first() 方法,线程 B 将会调用 third() 方法,线程 C 将会调用 second() 方法。正确的输出是 "firstsecondthird"。

提示:

  • nums[1, 2, 3] 的一组排列
解题思路

每个线程打印一个单词,但要控制每个线程打印时的次序。通过阻塞和非阻塞的方式都可以达到这个效果。

同步阻塞

通过锁和标识符控制,三个打印方法使用同一个对象锁。同一时间只能有一个获取到锁对象,如果是first线程则直接打印,然后更改first标识为true,调用notifyAll()方法唤醒等待线程;其它线程根据标识符判断是否打印,若不打印则调用wait方法,释放锁。

class Foo {

    private boolean first = false;
    private boolean second = false;

    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {

        synchronized (this) {
            printFirst.run();
            first = true;
            this.notifyAll();
        }
    }

    public void second(Runnable printSecond) throws InterruptedException {

        synchronized (this) {
            while (!first) {
                this.wait();
            } 

            printSecond.run();
            second = true;
            this.notifyAll();
        }
        // 这种写法的问题在于没搞明白线程间的通信后,被唤醒后,是从wait()方法返回,
        // 不是重新执行synchronized 区域代码
        /*if (first) {
        printSecond.run();
            second = true;
            this.notifyAll();
        } else {
            this.wait();
        }*/
    }

    public void third(Runnable printThird) throws InterruptedException {

        synchronized (this) {
            while (!second) {
                this.wait();
            } 

            printThird.run();
        }
    }
}
无锁编程

不加锁,三个线程不间断执行,通过一个volatile变量来控制打印次序。

class Foo {

    private volatile int a = 1;

    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {

        while (true) {
            printFirst.run();
            a = 2;
            break;
        }
    }

    public void second(Runnable printSecond) throws InterruptedException {

        while (true) {
            if (a == 2) {
                printSecond.run();
                a = 3;
                break;
            }
        }
    }

    public void third(Runnable printThird) throws InterruptedException {

        while (true) {
            if (a == 3) {
                printThird.run();
                break;
            }    
        }
    }
}

交替打印

题干描述

给你一个类:

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 实例:

  • 线程 A 将会调用 foo() 方法,而
  • 线程 B 将会调用 bar() 方法

请设计修改程序,以确保 "foobar" 被输出 n 次。

示例 1:

输入: n = 1
输出: "foobar"
解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。

示例 2:

输入: n = 2
输出: "foobarfoobar"
解释: "foobar" 将被输出两次。

提示:

  • 1 <= n <= 1000
解题思路

需要在两个循环中使两个线程交替执行打印,要使两个线程交替执行,这两个线程必须得使用同一个对象锁,然后进行线程间协作。同时,要使得两个线程交替执行,还需要一个标志符,表明现在应该那个线程执行打印。

有些使用无锁编程,通过Thread.yield()、Thread.sleep(1)来控制线程的执行次序,这是不靠谱的。因为让出CPU时间后,由操作系统指定那一个线程执行,这个过程比较随机,没法完全保证执行次序。

class FooBar {
    private int n;

    public FooBar(int n) {
        this.n = n;
    }

    private int a = 1;
    
    private Object lock = new Object();
   
    public void foo(Runnable printFoo) throws InterruptedException {

        synchronized (lock) {
            for (int i = 0; i < n; i++) {
                if (a == 2) {
                    lock.wait();
                }
                printFoo.run();
                a = 2;
                lock.notify();
            }
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {

        synchronized (lock) {
            if (a == 1) {
                lock.wait();
            }
            for (int i = 0; i < n; i++) {
                if (a == 1) {
                    lock.wait();
                }
                printBar.run();
                a = 1;
                lock.notify();
            }
        }
    }
}

标签:实题,调用,void,力扣,second,线程,多线程,public,first
From: https://www.cnblogs.com/cd-along/p/18211137

相关文章

  • Java 多线程编程基础
    我们的应用程序都是运行在多线程的环境下的,在多线程环境下的许多问题我们都了解吗?线程间如何进行数据交换?线程间如何进行通信与协作?共享一个资源时如何保证线程安全?线程数据交换线程之间无法直接访问对方工作内存中的变量,必须通过主内存进行变量的传递。例如,线程A、B共享一......
  • python多线程
    1、当程序中有耗时操作时,我们应该使用多线程来进行操作。多线程就像是多辆火车,可以在不同的轨道上同时运行。而进程就像是火车站,正在运行的一个程序的实例。python中多线程可以提供threading模块来实现。简单的多线程案例:importthreadingimporttime#定义线程执行的......
  • 多线程抢沙包游戏
    幼儿园玩抢沙包游戏,共计100个沙包,有10个小朋友(4男6女),男生每次拿3个沙包,女生每次拿2个沙包,如果剩余的沙包不够每次拿的数量,则游戏停止,请用java多线程模拟上述游戏过程。importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.CountDownLatch;import......
  • 深入解析Python并发的多线程和异步编程
    在Python编程中,多线程是一种常用的并发编程方式,它可以有效地提高程序的执行效率,特别是在处理I/O密集型任务时。Python提供了threading模块,使得多线程编程变得相对简单。本文将深入探讨threading模块的基础知识,并通过实例演示多线程的应用。1.多线程基础概念在开始之前,让我们......
  • WinSock 的多线程编程
    目录概述Winsock为什么需要多线程阻塞模式和非阻塞模式单线程和多线程的优缺点Win32系统下的多进程多线程机制进程和线程线程创建线程同步线程通信  VC++对多线程网络编程的支持MFC中的多线程支持ATL中的多线程支持多线程FTP客户端实例头文件包含线......
  • 基于Python的性能优化--多线程、协程、多进程
    合集-Python(1) 1.基于Python的性能优化05-24收起 一、多线程在CPU不密集、IO密集的任务下,多线程可以一定程度的提升运行效率。importthreadingimporttimeimportrequestsdeffetch_url(url:str)->None:'''根据地址发起请求,获取响应-url:......
  • Leetcode 力扣97. 交错字符串 (抖音号:708231408)
    给定三个字符串 s1、s2、s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:s=s1+s2+...+snt=t1+t2+...+tm|n-m|<=1交错 是 s1+t1+s2+t......
  • 使用python uiautomation模块,结合多线程快速寻找控件
    文章目录1.形式一2.形式二1.形式一该方法使用多线程进行搜索,主线程不会等待所有子线程返回结果后再继续执行,而是在获取队列中第一个结果后立即继续执行。优势在于一旦有子线程找到结果,主线程就能立即继续执行;劣势在于未找到结果的子线程会持续搜索,直到达到设定的最大......
  • Java JUC&多线程 基础完整版
    JavaJUC&多线程基础完整版目录JavaJUC&多线程基础完整版1、多线程的第一种启动方式之继承Thread类2、多线程的第二种启动方式之实现Runnable接口3、多线程的第三种实现方式之实现Callable接口4、多线的常用成员方法5、线程的优先级6、守护线程7、线程的让出8、线程插队9、同......
  • 力扣 3.无重复字符的最长字串
    题目描述:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串的长度。示例 1:输入:s="abcabcbb"输出:3解释:因为无重复字符的最长子串是"abc",所以其长度为3。示例2:输入:s="bbbbb"输出:1解释:因为无重复字符的最长子串是"b",所以其长度为1。......