多线程面试手撕题

本文探讨了在多线程环境中如何确保特定方法按序执行的解决方案,通过使用synchronized关键字和Semaphore信号量来实现线程间的同步和等待,确保了方法调用的正确顺序,避免了竞态条件。
  1. 按序打印
    我们提供了一个类:

public class Foo {
public void one() { print(“one”); }
public void two() { print(“two”); }
public void three() { print(“three”); }
}
三个不同的线程将会共用一个 Foo 实例。

线程 A 将会调用 one() 方法
线程 B 将会调用 two() 方法
线程 C 将会调用 three() 方法
请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。

示例 1:

输入: [1,2,3]
输出: “onetwothree”
解释:
有三个线程会被异步启动。
输入 [1,2,3] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 two() 方法,线程 C 将会调用 three() 方法。
正确的输出是 “onetwothree”。
示例 2:

输入: [1,3,2]
输出: “onetwothree”
解释:
输入 [1,3,2] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 three() 方法,线程 C 将会调用 two() 方法。
正确的输出是 “onetwothree”。

class Foo {
    private boolean firstFinished;
    private boolean secondFinished;
    private Object lock = new Object();
    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {
        
        // printFirst.run() outputs "first". Do not change or remove this line.
        synchronized(lock){
        printFirst.run();
        firstFinished =true;
        lock.notifyAll();
        }

    }

    public void second(Runnable printSecond) throws InterruptedException {
        
        // printSecond.run() outputs "second". Do not change or remove this line.
        synchronized(lock){
            while(!firstFinished){
                lock.wait();
            }
          printSecond.run();
          secondFinished = true;
          lock.notifyAll();
        }

    }

    public void third(Runnable printThird) throws InterruptedException {
        
        // printThird.run() outputs "third". Do not change or remove this line.
        synchronized(lock){
            while(!secondFinished){
                lock.wait();
            }
             printThird.run();
        }

    }
}
  1. 交替打印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 实例。其中一个线程将会调用 foo() 方法,另一个线程将会调用 bar() 方法。

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

class FooBar {
private int n;
private Semaphore foo = new Semaphore(1);
private Semaphore bar = new Semaphore(0);
public FooBar(int n) {
this.n = n;
}

public void foo(Runnable printFoo) throws InterruptedException {
    
    for (int i = 0; i < n; i++) {
        foo.acquire();
    	// printFoo.run() outputs "foo". Do not change or remove this line.
    	printFoo.run();
        bar.release();
    }
}

public void bar(Runnable printBar) throws InterruptedException {
    
    for (int i = 0; i < n; i++) {
        bar.acquire();
        // printBar.run() outputs "bar". Do not change or remove this line.
    	printBar.run();
        foo.release();
    }
}

}

### C++ 多线程编程实现示例与面试解析 C++11 标准引入了对多线程的原生支持,使得开发者能够更方便地编写并发程序。以下是一些常见的 C++ 多线程编程实现示例及面试解析。 #### 线程创建与管理 在 C++ 中,使用 `std::thread` 类来创建和管理线程。下面是一个简单的例子,展示了如何启动一个新的线程并等待它完成: ```cpp #include <iostream> #include <thread> void threadFunction() { std::cout << "Hello from thread!" << std::endl; } int main() { std::thread t(threadFunction); // 创建新线程,并执行函数 std::cout << "Hello from main!" << std::endl; t.join(); // 等待线程t结束 return 0; } ``` 当需要传递参数给线程函数时,可以直接将它们作为额外的参数提供给 `std::thread` 构造函数: ```cpp #include <iostream> #include <thread> void threadFunction(int x) { std::cout << "Value from thread: " << x << std::endl; } int main() { std::thread t(threadFunction, 42); // 向线程函数传参 t.join(); return 0; } ``` #### 线程同步 线程间通信通常涉及共享数据的问,为了防止竞态条件(race condition),我们需要使用互斥量(mutex)来保护共享资源。下面的例子演示了如何使用 `std::mutex` 和 `std::lock_guard` 来确保同一时间只有一个线程可以访问共享资源: ```cpp #include <iostream> #include <thread> #include <vector> #include <mutex> std::mutex mtx; // 定义一个互斥量 int counter = 0; void incrementCounter() { for (int i = 0; i < 100000; ++i) { std::lock_guard<std::mutex> lock(mtx); // 自动加锁/解锁 ++counter; } } int main() { std::vector<std::thread> threads(10); for (auto& t : threads) { t = std::thread(incrementCounter); } for (auto& t : threads) { t.join(); } std::cout << "Final counter value: " << counter << std::endl; return 0; } ``` #### 面试解析:生产者-消费者模型 生产者-消费者问是经典的多线程同步问之一。在这个模型中,生产者线程生成数据放入缓冲区,而消费者线程从缓冲区取出数据进行处理。为了解决这个问,我们可以利用条件变量 `std::condition_variable` 来协调两个或多个线程的工作: ```cpp #include <queue> #include <thread> #include <mutex> #include <condition_variable> std::queue<int> producedItems; std::mutex m; std::condition_variable cv; bool done = false; void producer() { for (int i = 0; i < 10; ++i) { std::unique_lock<std::mutex> lock(m); producedItems.push(i); std::cout << "Produced item " << i << std::endl; lock.unlock(); cv.notify_one(); // 通知一个等待中的消费者 std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟耗时操作 } { std::lock_guard<std::mutex> lock(m); done = true; } cv.notify_all(); // 所有生产完毕后通知所有消费者 } void consumer() { while (true) { std::unique_lock<std::mutex> lock(m); cv.wait(lock, []{ return !producedItems.empty() || done; }); if (done && producedItems.empty()) break; int item = producedItems.front(); producedItems.pop(); std::cout << "Consumed item " << item << std::endl; lock.unlock(); } } int main() { std::thread p(producer); std::thread c(consumer); p.join(); c.join(); return 0; } ``` 上述代码实现了基本的生产者-消费者模式,其中通过 `std::condition_variable` 控制线程间的同步[^1]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值