新的笔记,继续冲!!!随手整理的,有错误的话轻喷,谢谢,哈哈哈。
先从问题引入:使用两个线程打印1-100,线程1、线程2交替打印。
首先分析一下:这是一个多线程问题,就要涉及到线程的安全,看过前面的博客,再来实现这个问题肯定不难,但是还要满足交替这个条件,这就要通过线程之间的通信来解决。线程1打印完一个就要通知线程2来打印。
1.涉及的方法
- wait():当前线程阻塞,释放同步监视器
- notify():唤醒一个被阻塞的线程。如果有多个线程被阻塞,唤醒优先级高的(相同则随机
- notifyall():唤醒全部阻塞的线程
2.方法的说明
- wait(),notify(),notifyall()只能在同步代码块或者同步方法中,Lock锁的通信有其他方法。
- 三个方法的调用者必须是同步代码块或同步方法中的同步监视器(保持一致即可),不然IllegalMonitorStateException。
- 这三个方法定义在java.lang.Object类中。既然任何对象都可以充当同步监视器,干脆就声明在Object中咯。
3.交替打印数-实现代码
class Number implements Runnable{
private int number = 1;
@Override
public void run() {
while (true){
synchronized (this) {
notify();
if(number<=100){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + number);
number++;
try {
//使得调用如下wait()方法的线程阻塞,并释放监视器(锁)
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}//a执行完放开锁,a和b谁抢到了执行
}
}
}
public class ThreadMessage {
public static void main(String[] args) {
Number num = new Number();
Thread t1 = new Thread(num);
Thread t2 = new Thread(num);
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
4.生产者消费者问题剖析
生产者(Producer)将产品交给店员(Clerk),而消费者(Consumer)从店员处取走产品,店员只能持有固定数量的产品(20),如果消费者试图生产过多的产品,店员会叫生产者停一下,有了空位再继续生产;如果店里没有产品了,店员会叫消费者等一下,有货了再来取走产品。
分析:
- 是否涉及到多线程问题? 是,生产者线程,消费者线程
- 是否有共享数据? 是,店员持有的数量
- 如何解决线程安全问题? 同步机制,三种方法
- 是否涉及线程的通信? 是
5.生产者消费者问题-代码实现
public class ProducerAndConsumer {
public static void main(String[] args) {
//共享数据在Clerk中,至始至终只创建了一个clerk,对于同步方法拿到的默认
//同步监视器this(回顾一下),可以知道生产者和消费者是同一个监视器。
Clerk clerk = new Clerk();
Producer p1 = new Producer(clerk);
p1.setName("生产者1");
Consumer c1 = new Consumer(clerk);
c1.setName("消费者1");
p1.start();
c1.start();
}
}
class Clerk{
private int ProductCount = 0;
//生产产品
public synchronized void AddCount() {
if(ProductCount < 20){
ProductCount++;
System.out.println(Thread.currentThread().getName() + "开始生产第" + ProductCount + "个产品");
notify();//生产一个就可以唤醒生产者开始消费了
}else {//等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//消费产品
public synchronized void SubCount() {
if(ProductCount > 0){
System.out.println(Thread.currentThread().getName() + "开始消费第" + ProductCount + "个产品");
ProductCount--;
notify();//消费一个就可以唤醒生产者开始生产了
}else {//等待
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Producer extends Thread{//生产者
private Clerk clerk;
public Producer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":开始消费产品...");
while (true){//想看交替打印的可以在这加Thread.sleep()。
// 生产者刚释放锁,又大概率被生产者抢到了!!!
clerk.AddCount();
}
}
}
class Consumer extends Thread{//消费者
private Clerk clerk;
public Consumer(Clerk clerk){
this.clerk = clerk;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":开始生产产品...");
while (true){
clerk.SubCount();
}
}
}