当前位置: 首页 > news >正文

中石油网页设计与网站建设外链发布平台有哪些

中石油网页设计与网站建设,外链发布平台有哪些,研发网站要多久,网站内外链怎么做今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客_CSDN博客-Java2301 零、 复习昨日 一、作业 二、线程安全的集合 三、死锁 四、线程通信 五、生产者消费者 六、线程池 零、 复习昨日 创建线程的几种方式 1) 继承 2) 实现Runnable 3) calla…

今日内容

上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili
同步笔记沐沐霸的博客_CSDN博客-Java2301
零、 复习昨日
一、作业
二、线程安全的集合
三、死锁
四、线程通信
五、生产者消费者
六、线程池

零、 复习昨日

创建线程的几种方式 1) 继承 2) 实现Runnable 3) callable接口 Future接口 4) 线程池
启动线程的方法 start()
线程的几种状态
什么是线程不安全


setName getName
Thread.currentThread()
join
sleep


synchronized

一、作业

售卖后车票

package com.qf.homework;/*** --- 天道酬勤 ---** @author QiuShiju* @desc*/
public class Window implements Runnable {// 票(加static,被该类所有对象共享)private static int ticket = 100;// 售票任务@Overridepublic void run() {while (true) {synchronized (Window.class) {if (ticket > 0) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace( );}System.out.println(Thread.currentThread( ).getName( ) + "有余票,正在售出" + ticket);ticket--;} else {System.out.println("票已售完");return;}}}}
}
    public static void main(String[] args) {new Thread( new Window() ,"窗口1").start();new Thread( new Window() ,"窗口2").start();new Thread( new Window() ,"窗口3").start();}

二、线程安全的集合[了解]

StringBuffer是线程安全的,是因为每个方法都加上synchronized,即都是同步方法
StringBuilder没有加

image-20230303094122011

image-20230303094159112

ArrayList是线程不安全
Vector 是线程安全

image-20230303094527278

HashMap 是线程不安全
Hashtable 是线程安全

image-20230303095012216

比HashMap安全,比Hashtable快,即安全又快的集合ConcurrentHashMap[很重要]

三、死锁[了解]

死锁: 互相持有对方的锁还不释放

public class MyLock {static Object zuo = new Object();static Object you = new Object();
}
public class Boy extends Thread{@Overridepublic void run() {synchronized (MyLock.zuo){System.out.println("男朋友-拿到左筷子" );synchronized (MyLock.you) {System.out.println("男朋友-拿到右筷子,开吃" );}}}
}
public class Girl extends Thread{@Overridepublic void run() {synchronized (MyLock.you){System.out.println("女朋友-拿到右筷子" );synchronized (MyLock.zuo) {System.out.println("女朋友-拿到左筷子,开吃" );}}}
}
public class TestDeadLock {public static void main(String[] args) {new Boy().start();new Girl().start();}
}

男生先拿到zuo锁,再去获得you锁即可吃饭
但是you锁在女生那里,女生需要获得zuo锁才能吃饭
即 男生需要的you锁被女生拿着,女生需要的zuo锁被男生拿着
互相持有对方的锁,还不释放,就会出现"死锁" 程序卡死,不往下执行,持续阻塞

四、线程通信[熟悉]

4.1 介绍

线程通信,就是线程之间产生联系.

即通知,例如线程A执行到一定时候会停下,同时通知另外的线程B执行,
线程B执行到一定时候,也停下,通知线程A执行

以上操作需要Object类的方法

  • wait() 让当前线程等待
  • notify() 唤醒一个处于等待状态的线程
  • notifyAll() 唤醒所有处于等待状态的线程

4.2 两个个线程通信

需求: 昨天打印机方法,让print1()和print2()方法交替执行

package com.qf.notify;/*** --- 天道酬勤 ---** @author QiuShiju* @desc 打印机类*/
public class Printer {// 具体哪台打印机执行的标志private int flag = 1;// 现在使用同步方法,print1和print2方法由同一个对象打印机对象调用// print1方法和print2方法锁是同一个,是this,即打印机对象public synchronized void print1() {if (flag != 1) {try {// 锁是谁,就用谁调用wait// 当前线程就陷入等待,会让出资源释放锁this.wait();} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("1 ");System.out.print("2 ");System.out.print("3 ");System.out.print("4 ");System.out.print("\r\n");// 干完活,修改标志flag = 2;// 通知另外一个处于等待状态的线程// 锁是谁,用谁调用方法this.notify();}public synchronized void print2() {if (flag != 2) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("A ");System.out.print("B ");System.out.print("C ");System.out.print("D ");System.out.print("\r\n");flag = 1;this.notify();}
}
// 测试
public class TestNotify {public static void main(String[] args) {Printer printer = new Printer( );new Thread(){@Overridepublic void run() {while (true){printer.print1();}}}.start();new Thread(){@Overridepublic void run() {while (true){printer.print2();}}}.start();}
}

换用同步代码块实现

package com.qf.notify;/*** --- 天道酬勤 ---** @author QiuShiju* @desc 打印机类*/
public class Printer {// 锁对象private Object obj = new Object();// 具体哪台打印机执行的标志private int flag = 1;// 现在使用同步方法,print1和print2方法由同一个对象打印机对象调用// print1方法和print2方法锁是同一个,是this,即打印机对象public void print1() {// 同步代码块,现在锁是字节码文件synchronized(Printer.class) {if (flag != 1) {try {// 锁是谁,就用谁调用wait// 当前线程就陷入等待,会让出资源释放锁// 用字节码锁来调用wait方法Printer.class.wait( );} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("1 ");System.out.print("2 ");System.out.print("3 ");System.out.print("4 ");System.out.print("\r\n");// 干完活,修改标志flag = 2;// 通知另外一个处于等待状态的线程// 只能唤醒在此对象监视器(加过锁的)上等待的单个线程.// 如果没有加锁,直接调用该方法唤醒线程,会报错IllegalMonitorStateException// 锁是谁,用谁调用方法Printer.class.notify( );}}public  void print2() {synchronized( Printer.class) {if (flag != 2) {try {Printer.class.wait( );} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("A ");System.out.print("B ");System.out.print("C ");System.out.print("D ");System.out.print("\r\n");flag = 1;Printer.class.notify( );}}
}

4.3 练习

创建A1 A2 两个线程,分别打印1-10,11-20,保证A1执行完再 执行A2线程,A2执行完再执行A1

A1 —> 1
A2 —>11
A1 —> 2
A1 —>12

package com.qf.notify;/*** --- 天道酬勤 ---** @author QiuShiju* @desc*/
public class A1 extends Thread{@Overridepublic void run() {synchronized (TestA1A2.class) {for (int i = 1; i < 11; i++) {if (TestA1A2.flag != 1) {try {TestA1A2.class.wait();} catch (InterruptedException e) {e.printStackTrace( );}}System.out.println("A1 --> " + i);TestA1A2.flag  = 2;TestA1A2.class.notify();}}}
}
class A2 extends Thread{@Overridepublic void run() {synchronized (TestA1A2.class) {for (int i = 11; i < 21; i++) {if (TestA1A2.flag != 2) {try {TestA1A2.class.wait();} catch (InterruptedException e) {e.printStackTrace( );}}System.out.println("A2 --> " + i);TestA1A2.flag  = 1;TestA1A2.class.notify();}}}
}
class TestA1A2{static int flag = 1;public static void main(String[] args) {new  A1().start();new  A2().start();}
}

4.4 三个线程的通信

第一次
线程3抢到,判断标志是1,不是自己执行,改动标志为2,随机唤醒一条线程,但是此时所有线程都处于就绪状态,唤醒不唤醒无所谓…


第二次
假如线程2抢到,判断标志是2,自己执行,改动标志为3,随机唤醒一条线程,但是此时所有线程都处于就绪状态,唤醒不唤醒无所谓…


第三次
假如线程3抢到,判断标志是3,自己执行,改动标志为1,随机唤醒一条线程,但是此时所有线程都处于就绪状态,唤醒不唤醒无所谓…


第四次
假如这次又是线程3抢到,判断标志是1,不是自己执行,线程3陷入等待状态,让出资源
如果此时线程2抢到,判断标志是1,不是自己执行,线程2陷入等待状态,让出资源
此时只能线程1执行,判断标志是1,自己执行,改动标志为2,随机唤醒一条线程,如果唤醒是线程3,线程3从等待状态起来后通过while继续判断标志,发现不是自己,继续等待.此时只有线程1活跃,那么线程1执行,判断标志发现不是自己,陷入等待

解决方案: 全部唤醒 ,使用方法notifyAll(),唤醒所有处于等待状态的线程

package com.qf.notify;/*** --- 天道酬勤 ---** @author QiuShiju* @desc 打印机类*/
public class Printer2 {private int flag = 1;public void print1() {synchronized(Printer2.class) {// 改成while,让线程被唤醒后,继续判断// 如果是自己就执行,不是自己的标志就继续休眠while (flag != 1) {try {// 哪里等待,哪里起来继续执行Printer2.class.wait( );} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("1 ");System.out.print("2 ");System.out.print("3 ");System.out.print("4 ");System.out.print("\r\n");flag = 2;// 唤醒的是一条处于等待状态的线程(随机唤醒一条)// Printer2.class.notify( );// 唤醒所有等待的线程Printer2.class.notifyAll( );}}public  void print2() {synchronized( Printer2.class) {while (flag != 2) {try {Printer2.class.wait( );} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("A ");System.out.print("B ");System.out.print("C ");System.out.print("D ");System.out.print("\r\n");flag = 3;Printer2.class.notifyAll( );}}public  void print3() {synchronized( Printer2.class) {while (flag != 3) {try {Printer2.class.wait( );} catch (InterruptedException e) {e.printStackTrace( );}}System.out.print("一 ");System.out.print("二 ");System.out.print("三 ");System.out.print("四 ");System.out.print("\r\n");flag = 1;Printer2.class.notifyAll( );}}
}

第一次
线程3抢到,判断标志是1,不是自己执行,线程3陷入等待状态,让出资源


第二次
线程2抢到,判断标志是1,不是自己执行,线程2陷入等待状态,让出资源


第三次
线程1抢到,判断标志是1,自己执行,改动标志为2,随机唤醒一条线程
假如唤醒的是线程2,判断标志是2,自己执行,改动标志为3,唤醒线程3
但是假设线程2抢到,判断标志不是自己,线程2等待
假设线程1抢到,判断标志为3,不是自己,线程1也等待
线程3抢到资源开始执行,改动标志为1
随机唤醒一条线程,假如唤醒的线程2,现在判断标志是1,不是自己执行
线程2继续等待,现在活着的是线程3,抢到资源,判断标志不是自己,继续等待

4.5 总结

特殊的:

  • wait和notify方法需要在同步方法或者同步代码块内执行
  • wait会让当前线程进入等待状态,让出资源,其他线程可以执行
  • wait和notify()方法谁调用? 当前锁对象是谁,就是谁调用该方法

问 wait和sleep有什么区别?

答:

  • wait是Object类的方法,sleep是Thread类方法

  • wait和sleep都可以让当前线程进入阻塞状态

  • 但是wait阻塞当前线程,会让出系统资源,其他线程可执行;但是sleep阻塞当前线程,会持有锁不释放,其他线程无法执行

  • wait需要在同步方法或同步代码快中使用,但是sleep可以在同步或非同步都可以使用


问 为什么wait和notify方法要设计在Object类中?

答: 因为锁可以是任意对象,又因为wait和notify需要被 锁对象调用,那么锁对象是任意的,wait和notify方法也能被任意对象调用,所以就设计在Object类中,因为Object类是所有类的父类

五、生产者消费者

若干个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置⼀个能存储多个产品的缓冲区,生产者将生产的产品放入缓冲区中,消费者从缓 冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到⼀个空的缓冲区中取产品,也不允许生产者向⼀个满的缓冲区中放入产品。

商品类 Phone
商店类 Shop

package com.qf.pc;/*** --- 天道酬勤 ---** @author QiuShiju* @desc*/
public class Phone {String name;public Phone(){}public Phone(String name){this.name = name;}
}
class Shop {Phone phone;// 进货(生产)public synchronized void putPhone(Phone phone) {if (this.phone != null) {// 有货,先等待,让别人消费try {this.wait();} catch (InterruptedException e) {e.printStackTrace( );}}// 进货this.phone = phone;System.out.println("进货,"+phone.name );// 通知消费this.notify();}// 售货(消费)public synchronized void sellPhone() {if (this.phone == null) {// 没有商品,不能消费,先等待生产try {this.wait();} catch (InterruptedException e) {e.printStackTrace( );}}// 消费System.out.println("消费,"+phone.name );this.phone = null;// 通知生产this.notify();}
}
class TestPC {public static void main(String[] args) {Shop shop = new Shop( );// 生产者线程new Thread(){@Overridepublic void run() {for (int i = 1; i < 6; i++) {shop.putPhone(new Phone("IPhone"+i));}}}.start();// 消费者线程new Thread(){@Overridepublic void run() {for (int i = 1; i < 11; i++) {shop.sellPhone();}}}.start();}
}

六、线程池

6.1 线程池概念

  • 如果有非常多的任务需要非常多的线程来完成,每个线程的工作时间不长,就需要创建很多线程,工作完又立即销毁[线程频繁创建和销毁线程]
  • 频繁创建和销毁线程非常消费性能,那么线程池,就是可以创建一些线程,放在"池子"中,用的时候去池子取一个线程去使用,使用完再放回去,线程可以重用
  • 线程池,底层其实就是集合队列,里面存储线程对象,用的时候去抽即可,就不要频繁创建线程了

使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资
源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者
“过度切换”的问题 --> 摘自阿里官方手册

6.2 线程池原理

image-20230301230326324

将任务(task)提交(submit/execute)给线程池(threadpool),由线程池分配线程,运行任务,任务结束后,线程重新放入线程池供后续线程使用

6.3 创建线程池的方式

使用线程池创建线程,执行任务

JDK提供了关于线程池的一些类和接口

  • Executor: 线程池的根接口,通过execute(Runnable task) 执行任务
  • ExecutorService: Executor的子接口,通过submit(Runnable task) 来提交任务,执行任务
  • ThreadPoolExecutor: ExecutorService的子实现类,通过submit(Runnable task) 来提交任务,执行任务
  • Executors: 执行器类(线程池工厂类),通过该类来获得不同特点的线程池对象
    类中有很多静态方法,直接调用就可以获得各种特点线程池对象

6.4 不同特点的线程池

通过Executors调用以下静态方法获得不同特点的线程池对象

方法类型解释
newFixedThreadPool固定大小线程池池中包含固定数目的线程,空闲线程一直保留。只有核心线程,线程数量固定,任务队列为LinkedBlockingQueue
newCachedThreadPool动态大小的线程池,原则上无上限无核心线程,非核心线程数量无限,执行完闲置60s后回收,任务队列SynchronousQueue
newScheduledThreadPool可以执行定时任务的线程池用于调度执行的固定线程池,执行定时或周期性任务。和弦线程数量固定,非核心线程数量无线,执行完闲置10ms后回收,任务队列为DelayedWorkQueue
newSingleThreadExecutor单线程线程池只有一个线程的池,会顺序执行提交的任务,只有一个核心线程,无非核心线程,任务队列为LinkdBlockingQueue
newSingleThreadScheduledExecutor单线程定时任务线程池
newWorkStealingPool1.8提供新的方式创建线程池

以上线程池操作在阿里java开发手册中是不建议用的…

说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
-----------------------
OOM 内存溢出,即系统资源耗尽

线程池执行任务时,可以采用两种方法:

execute(): 没有返回值,无法判断任务是否执行成功

submit():会返回Future对象,通过该对象判断任务是否执行成功

    public static void main(String[] args) {// 固定大小线程池ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);for (int i = 0; i < 50; i++) {fixedThreadPool.execute(new Runnable( ) {@Overridepublic void run() {// System.out.println(Thread.currentThread().getName()+"干活" );}});}// 动态调整大小线程池ExecutorService fixedThreadPool2 = Executors.newCachedThreadPool();for (int i = 0; i < 50; i++) {fixedThreadPool2.execute(new Runnable( ) {@Overridepublic void run() {// System.out.println(Thread.currentThread().getName()+"干活" );}});}// 定时线程池ScheduledExecutorService  scheduledExecutor = Executors.newScheduledThreadPool(3);for (int i = 0; i < 5; i++) {scheduledExecutor.schedule(new Runnable( ) {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"干活" );}},3, TimeUnit.SECONDS);}}

6.5 ThreadPoolExecutor[重要]

  • ThreadPoolExecutor 很重要,有7个参数
参数名解释备注
int corePoolSize指定线程池的线程数量(核心线程数)不能小于0
int maximumPoolSize指定线程池可支持的最大线程数最大数量>=核心线程数
long keepAliveTime指定临时线程的最大存活时间不能小于0
TimeUnit unit指定存活时间的单位(秒,分,时,天)时间单位
BlockingQueue workQueue指定任务队列
ThreadFactory threadFactory指定哪个线程工厂创建线程
RejectedExecutionHandler handler指定线程忙,任务队列满的时候新任务来了怎么办?拒绝策略

问: 什么是创建临时线程?
答: 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建线程

问:什么时候开始拒绝任务?
答:核心线程和临时线程都在忙,任务队列也满了,新的任务过来就会拒绝

LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10);
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 15, 10, TimeUnit.SECONDS, queue);for (int i = 0; i < 50; i++) {poolExecutor.submit(new Runnable( ) {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"干活" );}});
}

今天这些都是会说,理解,能讲出来,不在于敲代码

http://www.dinnco.com/news/6671.html

相关文章:

  • 怎么建立免费的网站怎么做起泡胶
  • 三亚网站开发哪家好英文seo实战派
  • 5网站开发百度官网首页网址
  • 3合1网站建设全国疫情最新情况公布
  • 做网站的开发语言竞价服务托管公司
  • wordpress主题吧关键词优化价格表
  • 怎样做酒店网站ppt企业网站定制开发
  • 移动端app泰州seo平台
  • 上线了建站教程搜索引擎优化好做吗
  • 招商网站建设优势平台推广怎么做
  • 网站建设服务商 需要什么主机10条重大新闻事件
  • 网站模板登录模块公司推广宣传文案
  • 能力建设和继续教育中心网站北京网站优化经理
  • 做六合彩网站上海广告推广
  • 网站建站公司哪家好推广引流渠道
  • app制作公司十强seo关键词排名优化销售
  • 用自己的电脑做视频网站吗如何给自己的公司建网站
  • 自己做的网站设定背景图像产品推广的渠道有哪些
  • 广州制作外贸网站公司简介在线域名ip查询
  • 南京做网站好的公司搜索引擎营销怎么做
  • 网站标题优化工具获客渠道有哪些
  • 如何做游戏网站seo网站优化教程
  • 做视频网站收费侵权吗淘宝指数官网
  • 网站开发所需资料信息流广告接单平台
  • 做企业网站的意义拉新推广怎么找渠道
  • 如何做网站手机网站转让出售
  • 沈阳网站设计地推接单平台app排行榜
  • vs网站怎么做北京专业网站优化
  • delphi7网站开发免费推广软件下载
  • 南京外贸网站建设seo平台怎么样