初试多线程:
小栗子1:
/**
* @author nuo
* @version 1.0
* @description: TODO
* @date 2021/12/10 17:03
*/
/*
* 银行有一个账户。
* 有两个储户分别向同一个账户存3000元,每次存1000,存3次。
* 每次存完打印账户余额。
* <p>
* 分析:
* 1.是否是多线程问题?是,两个储户线程
* 2.是否有共享数据?有,账户(或账户余额)
* 3.是否有线程安全问题?有
* 4.需要考虑如何解决线程安全问题?同步机制:有三种方式。
*/
public class ThreadExer1 {
public static void main(String[] args) {
account acct = new account();
new Thread(new consumer(acct)).start();
new Thread(new consumer(acct)).start();
}
}
class account{
private int balance;
public synchronized void deposit(double amount){
if (amount > 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
balance += amount;
System.out.println(Thread.currentThread() + "成功存入 :" + amount + "¥");
System.out.println("账户余额 :" + balance);
}
}
}
class consumer implements Runnable {
private account acct;
public consumer(account acct) {
this.acct = acct;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
acct.deposit(1000);
}
}
}
小栗子2:
/**
* @author nuo
* @version 1.0
* @description: TODO 线程通信的应用:经典例题:生产者/消费者问题
* @date 2021/12/10 20:36
*/
/* 面试题:sleep() 和 wait()的异同?
*
* 1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
*
* 2.不同点:
* 1)两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait()
* 2)调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中
* 3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。
*/
/*
* 线程通信的应用:经典例题:生产者/消费者问题
*
* 生产者(Producer)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,
* 店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,
* 店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;
* 如果店中没有产品了,店员会告诉消费者等一下,
* 如果店中有产品了再通知消费者来取走产品。
*
* 分析:
* 1.是否是多线程的问题?是,生产者的线程,消费者的线程
* 2.是否有共享数据的问题?是,店员、产品、产品数
* 3.如何解决线程的安全问题?同步机制,有三种方法
* 4.是否涉及线程的通信?是
*/
public class ThreadExer2 {
public static void main(String[] args) {
Clerk c = new Clerk();
Producer p = new Producer(c);
Customer c_ = new Customer(c);
new Thread(p).start();
new Thread(c_).start();
}
}
class Producer implements Runnable {
private final Clerk c;
public Producer(Clerk c) {
this.c = c;
}
@Override
public void run() {
while (true) {
synchronized (c) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (c.getProduct() < 20) {
c.setProduct(c.getProduct() + 1);
System.out.println("生产者生产第" + c.getProduct() + "件产品...");
// 必须使用同步监视器去调用
c.notify();
}else {
try {
// 必须使用同步监视器去调用
c.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class Customer implements Runnable {
private final Clerk c;
public Customer(Clerk c) {
this.c = c;
}
@Override
public void run() {
while (true) {
synchronized (c) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (c.getProduct() > 0) {
System.out.println("消费者消费第" + c.getProduct() + "件产品...");
c.setProduct(c.getProduct() - 1);
// 必须使用同步监视器去调用
c.notify();
}else {
try {
// 必须使用同步监视器去调用
c.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class Clerk {
private int product;
public int getProduct() {
return product;
}
public void setProduct(int product) {
this.product = product;
}
}
PS:
在调用相应的 wait() notify() 时,必须确保使用的是对应的同步监视器,未显示声明,则默认为当前对象 ( 非static 类型 ) 或当前类 ( static 类型 ) 调用