线程通信
线程通信:有一个缓冲区的仓库,生产者线程,不断往仓库存储内容,消费者线程不断从仓库中获取内容。为了解决生产者和消费者的动态调节的问题,可以使用线程通信机制,来保护生产者和消费中的同步
// 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待线程状态从 运行 变更为 阻塞
void wait();
// 唤醒在此对象监视器上等待的单个线程,只能唤醒因为wait阻塞的线程。线程的状态从 阻塞 变更为 就绪
void notify();
// 唤醒在此对象监视器上等待的所有线程,只能唤醒因为wait阻塞的线程。线程的状态从 阻塞 变更为 就绪
void notifyAll();
wait、notify、notifyall 都是Object的方法、都需要使用在同步方法中
class Restaurant {
int count = 0;
public synchronized void make() {
if (count < 10) {
System.out.println(Thread.currentThread().getName() + "做了一道菜,当前还有" + (count + 1) + "道菜");
count++;
notifyAll();
} else {
try {
System.out.println("做完了赶紧卖");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void sell() {
if (count > 0) {
System.out.println(Thread.currentThread().getName() + "卖了一道菜,当前还有" + (count - 1) + "道菜");
count--;
notify();
} else {
try {
System.out.println("卖完了赶紧做");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestRestaurant {
public static void main(String[] args) {
Restaurant res = new Restaurant();
Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
res.make();
Thread.yield();
}
}
});
Thread th2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
res.make();
Thread.yield();
}
}
});
Thread th3 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
res.sell();
Thread.yield();
}
}
});
Thread th4 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
res.sell();
Thread.yield();
}
}
});
th1.setName("做饭小伙");
th2.setName("做饭姑娘");
th3.setName("卖饭小伙");
th4.setName("卖饭姑娘");
th1.start();
th2.start();
th3.start();
th4.start();
}
}
线程池
线程池:有效并充分利用线程,合理分配资源
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池
线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用
线程池的优点
1、控制线程数量
2、避免了频繁的创建和销毁线程
3、对线程进行统一的管理
Executors
Executors Java封装的创建线程池的工具类 现在已经被淘汰 因为很容易引起 OOM (Out of Memory) 异常
// 创建一个可重用的,具有固定线程数的线程池
newFixedThreadPool(int nThreads);
// 创建一个只有单线程的线程池,相当于上个方法的参数是1
newSingleThreadExecutor();
// 创建一个没有上限的线程池
newCachedThreadPool();
// 创建一个固定线程数量的线程池,这个线程池具备延迟、定时重复执行
newScheduledThreadPool();
// 创建一个抢占式的线程池
newWorkStealingPool();
ThreadPoolExecutor 类
目前推荐手动创建线程池
// 用给定的初始参数和默认的线程工厂及被拒绝的执行处理程序创建新的 ThreadPoolExecutor
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
参数说明:
corePoolSize - 设置最小线程数量。池中所保存的线程数,包括空闲线程。
maximumPoolSize - 池中允许的最大线程数。
keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
unit - keepAliveTime 参数的时间单位。
workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务
运行线程池
// 执行对应的线程
void execute(Runnable command);
// 关闭线程池
void shutdown();
案例代码
public class TestThreadPool {
public static void main(String[] args) {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 5, 1000, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10));
tpe.execute(new Runnable() {
int count = 0;
@Override
public void run() {
while (count < 5) {
try {
System.out.println("111");
count++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
tpe.execute(new Runnable() {
int count = 0;
@Override
public void run() {
while (count < 5) {
try {
System.out.println("222");
count++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
tpe.execute(new Runnable() {
int count = 0;
@Override
public void run() {
while (count < 5) {
try {
System.out.println("333");
count++;
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
tpe.shutdown();
}
}
版权属于:不冷
本文链接:https://www.buleng.xyz/archives/85/
转载时须注明出处及本声明