线程实现的方式
- 继承extends Thread类
- 实现Runnable接口
- 实现Callable接口
- 线程池:是一个线程队列,里面存放着很多个线程,可以减少因创建、销毁线程而花费的时间
java不能多继承,但是可以实现多个接口,所以使用Runnable接口会比继承Thread类更加灵活,一个类对象实现多个Runnable接口。
生产者/消费者模式-线程通信
包含生产者、消费者、和一个缓冲区。生产者->生产数据->缓冲区->取数据->消费者
生产者将生产的数据不直接发给消费者使用,而是将数据先存放到缓冲区。消费者从缓冲区取数据。
优点:
- 生产者与消费者之间的耦合度不大,是一个解耦过程
- 支持并发,生产者速度较快时,不必一直等待消费者处理完数据,而浪费掉时间。
- 起到一个缓存的作用,消费者处理来不及时,可以将未处理的数据先存放到缓冲区以供后面的使用
public class PCTest {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
Producer producer = new Producer(synContainer);
Consumer consumer = new Consumer(synContainer);
Consumer consumer1 = new Consumer(synContainer);
new Thread(producer).start();
new Thread(consumer).start();
new Thread(consumer1).start();
}
}
// 生产者
class Producer implements Runnable {
SynContainer synContainer;
public Producer(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synContainer.push(new Chicken(i));
}
}
}
// 消费者
class Consumer implements Runnable {
SynContainer synContainer;
public Consumer(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synContainer.pop();
}
}
}
// 产品
class Chicken {
int id;
public Chicken(int id) {
this.id = id;
}
}
// 缓冲区
class SynContainer {
// 需要一个容器
Chicken[] chickens = new Chicken[10];
// 容器计数器
int count = 0;
// 生产者放入产品
public synchronized void push(Chicken chicken) {
if(count == chickens.length) {
// 通知消费者,生产者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
chickens[count] = chicken;
System.out.println("生产id为" + chicken.id + ", count为" + count);
count++;
this.notify();
}
// 消费者消费产品
public synchronized Chicken pop() {
while(count == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
Chicken chicken = chickens[count];
System.out.println("消费了id为" + chicken.id + ", count为" + count);
this.notify();
return chicken;
}
}
sleep与wait的区别
sleep()
属于Thread
;wait()
属于Class,是Object类的方法,Object.wait()
sleep()
会传入一个时间,时间到了之后恢复为就绪状态;wait()
不传入时间,进入“无限期等待”,只通过notify()
唤醒。sleep
当前线程睡觉,但是不释放锁,其他线程不能使用锁住的资源,占着锁睡觉。因为线程睡觉时CPU空闲,所以它释放CPU执行权;wait
释放锁,可以理解为离开队列,等待被唤醒再进入,让其他人先使用资源,也释放CPU执行权。sleep
可以在任何地方使用;wait
只能在同步方法或同步代码块里使用。