首页 >> 大全

进程和线程以及线程池(二)

2023-12-05 大全 25 作者:考证青年

山不过来,我就过去

生产者-消费者模型

在前面我们讲了很多关于同步的问题,然而在现实中,需要线程之间的协作。比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权。因为生产者如果不释放对临界资源的占用权,那么消费者就无法消费队列中的商品,就不会让队列有空间,那么生产者就会一直无限等待下去。因此,一般情况下,当队列满时,会让生产者交出对临界资源的占用权,并进入挂起状态。然后等待消费者消费了商品,然后消费者通知生产者队列有空间了。同样地,当队列空时,消费者也必须等待,等待生产者通知它队列中有商品了。这种互相通信的过程就是线程间的协作。

总的来说,就是如下图的这样,不断循环。

以学生类为资源举例

首先,要对线程等待,唤醒有基本的思想

不同种类线程之间的通信(等待唤醒机制)

出现线程安全问题了:

1.是不是多线程环境

2.是不是由共享资源

3.是否有多条语句在操作共享资源

线程的等待唤醒 类

void wait ()

在其他线程调用此对象的 () 方法或 () 方法前,导致当前线程等待。

void ()

唤醒在此对象监视器上等待的单个线程。

void ()

唤醒在此对象监视器上等待的所有线程。

_线程池和进程池_线程池进程池

生产线程:如果没有资源资源我就生产,有了资源我就等待,通知消费线程来消费

消费线程:有了资源我就消费,没有资源我就等着,你通知生产线程生产

1)定义一个学生类,定义一个标记,代表有无资源。

public class Student {public String name;public int age;//定义一个标记boolean flag;//表示资源,false就没有,ture就有
}

2定义一个生产资源类

public class SetThread extends Thread {Student student;int i=0;public SetThread(Student student) {this.student=student;}@Overridepublic void run() {while (true){synchronized (student){if(student.flag){try {student.wait();} catch (InterruptedException e) {e.printStackTrace();}}if(i%2==0){student.name="老大";student.age=15;}else {student.name="老二";student.age=12;}student.flag=true;//通知student.notifyAll();//唤醒以后,还要再次争抢时间片i++;}}}
}

3)定义一个消费类

public class GetThread extends Thread {//获得资源Student student;public GetThread(Student student) {this.student=student;}@Overridepublic void run() {while (true){synchronized (student){if(!student.flag){//没有资源try {student.wait();//等着:wait()方法 线程一旦等待 就要立马释放锁,等会被唤醒了,也就从这里醒来} catch (InterruptedException e) {e.printStackTrace();}}System.out.println(student.name + "===" + student.age);//修改标记student.flag = false;student.notify();//通知}}}
}

4)接下来,开启线程

public class Test {public static void main(String[] args) {Student student = new Student();SetThread th1 = new SetThread(student);GetThread th2 = new GetThread(student);th1.start();th2.start();}
}

结果:

总的就是,生产-消费的关系一直循环(等待唤醒机制)

线程池的概述与使用 1)线程池概述

程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。

而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池

2)内置线程池的概述

JDK5新增了一个工厂类来产生线程池,有如下几个方法

public static ExecutorService newCachedThreadPool():                根据任务的数量来创建线程对应的线程个数    
public static ExecutorService newFixedThreadPool(int nThreads):    固定初始化几个线程
public static ExecutorService newSingleThreadExecutor():            初始化一个线程的线程池

这些方法的返回值是对象,该对象表示一个线程池,可以执行对象或者对象代表的线程。它提供了如下方法

( task)

( task)

使用步骤:

创建线程池对象

创建实例

提交实例

关闭线程

3)匿名内部类的方式实现多线程

a.继承Tread类

b.继承类

public class Thread {public static void main(String[] args) {//匿名实现多线程//继承thread类new Thread(){public void run(){for(int x=0;x<111;x++){System.out.println(getName()+":"+x);}}}.start();//实现runable    new Thread(new Runnable() {@Overridepublic void run() {for(int x=0;x<100;x++){System.out.println("wwww");}}}).start();}
}

4)工厂类来产生线程池

首先,定义一个类来继承,需要重新其中的call()方法。

public class MyCallable implements Callable {int len;public MyCallable(int i) {len=i;}@Overridepublic Integer call() throws Exception{//此方法需要返回值,int sum=0;for (int i = 0; i <= len; i++) {sum=sum+i;}return sum;}
}

接下来开启线程池。

public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {//Callable 这个任务接口,执行完之后会有返回值 跟线程池配合使用// Runnable 这个任务接口 执行完之后没有返回值//获取一个有指定数量线程对象的线程池ExecutorService service = Executors.newFixedThreadPool(3);//定义线程个数//submit  提交要执行的值返回任务,并返回表示挂起的任务结果的 Future。Future sb1 = service.submit(new MyCallable(10));//第一个线程Future sb2 = service.submit(new MyCallable(100));//Future sb3 = service.submit(new MyCallable(1000));System.out.println(sb1.get());System.out.println(sb2.get());System.out.println(sb3.get());service.shutdown();//关闭线程池}
}

记得最后关闭线程池。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了