线程协作线程通信08
线程协作以及通信
生产消费者问题
- 应用场景:
-
- 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费
- 如果仓库中没有产品,则生成者将产品放入仓库,否则停止生产,并等待,直到仓库中的产品被消费者取走为止
- 如果仓库中方有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止
- 这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间销户依赖,互为条件。
-
- 在生产者消费者问题中,仅有synchronized是不够的
- synchronized可阻止并发,更新同一个共享资源,实现了同步
- synchronized不能实现不同线程之前的消息传递(通信)
线程通信
| 方法名 | 作用 |
|---|---|
| wait() | 表示线程一直等待,直到其他线程通知,与sleep不同。会释放锁 |
| wait(long timeout ) | 指定等待的毫秒数 |
| notify() | 唤醒一个处于等待状态的线程 |
| notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程优先调度 |
注意:均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常lllegalMonitorStateException
管程法
并发协作模型"生产者/消费者"->管程法
- 生产者:负责生产数据的模块(可能是方法,对象,线程,进程);
- 消费者:负责处理数据的模块(可能是方法,对象,线程,进程);
- 缓冲区:消费者不能直接使用生产者的数据,他们之间有个"缓冲区"
package com.cnblo.www.Thread.coop;
public class ProcederSale {
public static void main(String args[])
{
Pools ps=new Pools();
new Proceder(ps,"食堂大妈").start();
new Custmer(ps,"小明").start();
new Custmer(ps,"小红").start();
}
}
//厨师,生产者
class Proceder extends Thread {
Pools p;//容器公用的
public Proceder(Pools p,String name) {
super(name);
this.p=p;
}
public void run()
{
for (int j=0;j<5;j++)
{
p.processFo(new Food(j));
}
}
}
//消费者
class Custmer extends Thread {
Pools p;//容器公用的
public Custmer(Pools p,String name) {
super(name);
this.p=p;
}
public void run()
{
for (int j=0;j<5;j++)
{
System.out.println(Thread.currentThread().getName()+"消费了---->第"+ p.eatFo().id+"号食品");
}
}
}
class Food extends Thread {
int id;
Pools p;
public void run() {
}
public Food(int id) {
this.id=id;
}
}
class Pools {
//装食物的容器
Food[] panzi=new Food[10];
//计数器
int counts=0;
//生产方法
public synchronized void processFo( Food f)
{
//如果满了就等待消费
if(counts==panzi.length) {
System.out.println("货存满了等待消费");
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//否则生产,放入容器,同时计数器加1
{
panzi[counts]=f;
System.out.println(Thread.currentThread().getName()+"生产食品编号为+++>"+f.id);
counts++;
//通知可以消费
this.notifyAll();
}
}
//消费的方法
public synchronized Food eatFo()
{
///如果容器为空就等待生产者生产
if(counts==0)
{
System.out.println("没食物了,等待生产");
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//否则就消费
//消费,计数器减一
{
counts--;
Food fd=panzi[counts]; //把要吃掉的事物保另存返回,一遍获取
//吃完了唤醒生产;不唤醒就会吃光一直等待
this.notifyAll();
return fd;
}
}
}
/*食堂大妈生产食品编号为+++>0
食堂大妈生产食品编号为+++>1
食堂大妈生产食品编号为+++>2
食堂大妈生产食品编号为+++>3
食堂大妈生产食品编号为+++>4
小明消费了---->第2号食品
小明消费了---->第4号食品
小红消费了---->第0号食品
小明消费了---->第3号食品
小红消费了---->第1号食品
没食物了,等待生产
没食物了,等待生产
*/
注意:感觉得保证两个线程的for循环次数一直,不然会最后持续等待;
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
信号灯法
并发协作模型"生产者/消费者"->信号灯法
- 通过一个标志位来判断,让线程等待或者唤醒。
package com.cnblo.www.guancheng;
public class Test03WatchMv {
public static void main(String args[]) {
Movie m=new Movie();
Employ e=new Employ(m);
Guster g=new Guster(m);
e.start();
g.start();
}
}
class Employ extends Thread{
Movie v;
public Employ(Movie v) {
this.v=v;
}
public void run() {
for (int i=0;i<10;i=i+1) {
v.createMovide("荒野求生"+i);
}
}
}
class Guster extends Thread{
Movie v;
public Guster(Movie v) {
this.v=v;
}
public void run()
{
for (int i=0;i<10;i++) {
v.wathcMovie();
}
}
}
class Movie{
String name;
boolean flags=true;
public Movie(String name) {
this.name=name;
}
public Movie() {
}
public synchronized void createMovide(String v) {
if(!flags)
{
System.out.println("等待观众观看"); //等待观众观看
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}{
this.name=v;
System.out.println("创作电影----+1"+this.name); //等待观众观看
flags=!this.flags; //创造电影后就改变标志位,下一次等待用户观看
this.notifyAll();
}
}
public synchronized void wathcMovie() {
if(flags)
{
System.out.println("等待电影开播"); //如果没电影电影就等待电影拍摄创造
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} {
//如果有电影就观看电影
System.out.println("用户观看了电影"+this.name);
flags=!this.flags;//观看电影后改表标志位等待下一场电影创造
this.notifyAll();//唤醒电影创造
}
}
}/*
等待电影开播
创作电影----+1荒野求生0
等待观众观看
用户观看了电影荒野求生0
等待电影开播
创作电影----+1荒野求生1
用户观看了电影荒野求生1
等待电影开播
创作电影----+1荒野求生2
用户观看了电影荒野求生2
等待电影开播
创作电影----+1荒野求生3
用户观看了电影荒野求生3
等待电影开播
创作电影----+1荒野求生4
用户观看了电影荒野求生4
等待电影开播
创作电影----+1荒野求生5
用户观看了电影荒野求生5
等待电影开播
创作电影----+1荒野求生6
等待观众观看
用户观看了电影荒野求生6
等待电影开播
创作电影----+1荒野求生7
用户观看了电影荒野求生7
等待电影开播
创作电影----+1荒野求生8
用户观看了电影荒野求生8
等待电影开播
创作电影----+1荒野求生9
用户观看了电影荒野求生9*/
使用线程池
-
背景:经常创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
-
思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁,实现重复利用。类似生活中的公共交通工具。
-
好处:
-
- 提高相应速度(减少了创建线程时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理(...)
-
- corePoolSize:核心池的大小
- maximumPoolSize:最大线程数
- keepAliveTime:线程没有任务时最多保持多长时间后会终止
-
JDK5.0提供了线程池相关API:ExecutorService和Executors
-
ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
-
- void execute(Runnable command):执行任务/命令,没有返回值,一般用来运行Runnable
Future submit(/Callable task):执行任务,有返回值,一般又来执行Callable - void shutdown():关闭连接池
-
Executors:工具类,线程池的工厂类,用于创建并返回不同类型的线程池
package com.cnblo.www.guancheng;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ThreadPool {
public static void main(String args[]) {
MyRunnables mr=new MyRunnables();
ExecutorService eservice=Executors.newFixedThreadPool(4);
eservice.execute(mr);
eservice.execute(mr);
eservice.execute(mr);
eservice.execute(mr);
eservice.execute(mr);
eservice.shutdown();
}
}
class MyRunnables implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
/*
pool-1-thread-1
pool-1-thread-4
pool-1-thread-3
pool-1-thread-2
pool-1-thread-1
*/
线程的总结
package com.cnblo.www.guancheng;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
//总结实现线程的几种方式
public class Zongjie {
public static void main(String args[]) {
new MyThreadTest01().start();
new Thread(new MyThreadTest02()).start();
ExecutorService et=Executors.newFixedThreadPool(1);//新建一个服务设定池子大小
Future<Integer> f=et.submit(new MyThreadTest03());
try {
System.out.println(f.get());//获取返回值
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
et.shutdown();//关闭服务
}
}
//方式一继承Thread
class MyThreadTest01 extends Thread{
public void run() {
System.out.println("继承Thread类");
}
}
//方式2实现Runnable
class MyThreadTest02 implements Runnable{
public void run() {
System.out.println("实现Runnable接口");
}
}
//方式3实现Callable接口注意,是有返回值的
class MyThreadTest03 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("实现Callable接口");
return 100;
}
}
浙公网安备 33010602011771号