概念:多个线程在处理同一个资源,但是处理的动作(各线程任务不同)
举例:(图片来自某网课,如有侵权联系删除)
处理线程间通信的原因:
由于要处理同一份资源,为了避免对同一资源的争夺,那么就需要对多线程之间进行协调,保证能够达到多线程正确处理同一个资源
(比如线程A生产完包子之后,线程B才能去消费)
概念 :这是多个线程之间的一种协作机制,在多线程之间有通信时, 通过使用wait notify等方法让线程有效并正确的利用同一个资源。
具体体现:在吃包子的例子中等待唤醒机制具体如下:(图片来自某网课,如有侵权联系删除)
注意事项
当某线程从waiting状态被唤醒时, 也有可能不会立即执行,需要看此时cpu是否空闲,也就是看此时就要看能不能获得锁,如果能获取锁,可执行进入Runnable状态,如果cpu不空闲,不能获取锁,那么该线程可能进入blocked状态。
wait方法和notify方法在调用时, 应该使用同一个锁对象:这样对应的锁对象会notify使用同一个锁对象调用的wait方法后的线程
wait方法和notify方法是属于Object类的(锁对象是可以是任意对象,而任意对象的所属类都是Object的子类)
wait方法和notify方法必须要在同一个代码块或者是同步代码函数中使用,因为:必须要通过锁对象调用这个方法
等待唤醒案例具体分析:(图片来自某网课,如有侵权联系删除)
等待唤醒机制代码实现(例子也来自某网课)
生产者线程:
public class Consumer extends Thread{
private Baozi bz;
public Consumer(Baozi bz) {
this.bz = bz;
}
@Override
public void run() {
while (true){
synchronized (bz){
if (bz.flag==false){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//被唤醒后就吃包子
System.out.println("The consumer is eating baozi with: " + bz.pi + bz.xian);
bz.flag = false;
bz.notify();
System.out.println("The baozi with: "+bz.pi + bz.xian + " has been eaten all, please produce one more");
System.out.println("==========================================");
}
}
}
}
}
消费者线程:
public class Consumer extends Thread{
private Baozi bz;
public Consumer(Baozi bz) {
this.bz = bz;
}
@Override
public void run() {
while (true){
synchronized (bz){
if (bz.flag==false){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//被唤醒后就吃包子
System.out.println("The consumer is eating baozi with: " + bz.pi + bz.xian);
bz.flag = false;
bz.notify();
System.out.println("The baozi with: "+bz.pi + bz.xian + " has been eaten all, please produce one more");
System.out.println("==========================================");
}
}
}
}
}
测试类:
public class Demo12Main {
public static void main(String[] args) {
//创建包子对象,作为包子铺线程和吃货线程的锁对象作为初始化参数通过构造方法传进去
Baozi baozi = new Baozi();
//创建消费者线程和包子线程
new Consumer(baozi).start();
new BaoziPu(baozi).start();
}
}
测试结果:
baozipu is making baozi with: thickchicken
baozi have been made ok with: thickchicken You may start eating!
++++++++++++++++++++++++++
The consumer is eating baozi with: thickchicken
The baozi with: thickchicken has been eaten all, please produce one more
==========================================
baozipu is making baozi with: thinbeef
baozi have been made ok with: thinbeef You may start eating!
++++++++++++++++++++++++++
The consumer is eating baozi with: thinbeef
The baozi with: thinbeef has been eaten all, please produce one more
==========================================
baozipu is making baozi with: thickchicken
baozi have been made ok with: thickchicken You may start eating!
++++++++++++++++++++++++++
The consumer is eating baozi with: thickchicken
The baozi with: thickchicken has been eaten all, please produce one more
==========================================
baozipu is making baozi with: thinbeef
baozi have been made ok with: thinbeef You may start eating!
++++++++++++++++++++++++++
The consumer is eating baozi with: thinbeef
The baozi with: thinbeef has been eaten all, please produce one more
==========================================
baozipu is making baozi with: thickchicken
baozi have been made ok with: thickchicken You may start eating!
++++++++++++++++++++++++++
The consumer is eating baozi with: thickchicken
The baozi with: thickchicken has been eaten all, please produce one more
==========================================
baozipu is making baozi with: thinbeef
baozi have been made ok with: thinbeef You may start eating!
++++++++++++++++++++++++++
The consumer is eating baozi with: thinbeef
The baozi with: thinbeef has been eaten all, please produce one more
==========================================
baozipu is making baozi with: thickchicken
baozi have been made ok with: thickchicken You may start eating!
++++++++++++++++++++++++++
The consumer is eating baozi with: thickchicken
The baozi with: thickchicken has been eaten all, please produce one more
==========================================
baozipu is making baozi with: thinbeef
线程池
线程池:其实就是一个容纳多个线程的容器,其中的线程可以反复循环利用,省去了频繁创建线程对象的操作,无需因为反复创建销毁线程而浪费系统资源。
线程池的工作原理如下图所示:
Java在JDK1.5以后就提供了线程池的工厂类
java.util.concurrent.Executors
static ExecutorService newFixedThreadPool(int nThreads)
创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。
参数:int nThreads:创建线程中包含的线程数量
返回值:ExecutorService:返回的是ExecutorService接口的实现类对象,我们可以使用ExecutorService接口来接收(面向接口)用来获取线程,调用start开始执行线程。
通过ExecutorService调用Future> submit(Runnable task)来提交一个Runnable用与执行
提交值返回任务以执行,并返回代表任务待处理结果的Future。未来的get
方法将在成功完成后返回任务的结果。
如果您想立即阻止等待任务,您可以使用result = exec.submit(aCallable).get();格式的result = exec.submit(aCallable).get();
注意: Executors
类包括一组方法,可以将一些其他常见的类似对象的对象,例如PrivilegedAction
转换为Callable
表单,以便它们可以提交。
参数类型
T
- 任务结果的类型
参数
task
- 提交的任务
结果
一个未来的代表,待完成任务
异常
RejectedExecutionException
- 如果任务无法安排执行
NullPointerException
- 如果任务为空
void shutdown()
启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务。如果已经关闭,调用没有额外的作用。
此方法不等待以前提交的任务完成执行。 使用awaitTermination
做到这一点。
线程池的使用步骤:(未完待续)
使用线程池的工厂类Executors 里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池
创建一个类来实现Runnable方法 ,重写run方法
调用ExecutorService中的submit方法,传递线程任务(实现类),开启线程执行run方法。
调用ExecutorService的shutdown,但是不建议使用,因为会销毁线程。
代码实现:
public static void main(String[] args) {
//1.使用线程池的工厂类Executors 里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池
ExecutorService es = Executors.newFixedThreadPool(3);
//3,调用ExecutorService中的submit方法,传递线程任务(实现类),开启线程执行run方法
es.submit(new RunnableImpl());//pool-1-thread-2create a new thread
//线程池会一直开启,使用完了线程,会自动把线程归还给线程池
es.submit(new RunnableImpl());//pool-1-thread-1create a new thread
es.submit(new RunnableImpl());//pool-1-thread-2create a new thread
es.submit(new RunnableImpl());//pool-1-thread-3create a new thread
//4.调用ExecutorService的shutdown,但是不建议使用,因为会销毁线程。
es.shutdown();
//销毁了所有线程后,线程池里就没有线程,因此执行下列语句就会报错。
es.submit(new RunnableImpl());
//Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@330bedb4 rejected from java.util.concurrent.ThreadPoolExecutor@2503dbd3[Shutting down, pool size = 3, active threads = 2, queued tasks = 0, completed tasks = 1]
// at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
// at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
// at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
// at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
// at com.kou.thread.demo12.Demo01ThreadPool.main(Demo01ThreadPool.java:19)
}
//2.创建一个类来实现Runnable方法 ,重写run方法
public class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"create a new thread");
}
}