Java(八)----多线程(二)
创始人
2024-03-12 05:56:05

1. 生产者与消费者

1.1 安全问题产生

  • 线程本身就是一个新创建的方法栈内存 (CPU进来读取数据)

  • 线程的notify(),唤醒第一个等待的线程

    • 解决办法 : 全部唤醒 notifyAll()

  • 被唤醒线程,已经进行过if判断,一旦醒来继续执行

    • 线程被唤醒后,不能立刻就执行,再次判断标志位,利用循环

    • while(标志位) 标志位是true,永远也出不去

/*** 定义资源对象*   成员 : 产生商品的计数器*          标志位*/
public class Resource {private int count ;private boolean flag ;//消费者调用public synchronized void getCount() {//flag是false,消费完成,等待生产while (!flag)//无限等待try{this.wait();}catch (Exception ex){}System.out.println("消费第"+count);//修改标志位,为消费完成flag = false;//唤醒对方线程this.notifyAll();}//生产者调用public synchronized void setCount() {//flag是true,生产完成,等待消费while (flag)//无限等待try{this.wait();}catch (Exception ex){}count++;System.out.println("生产第"+count+"个");//修改标志位,为生产完成flag = true;//唤醒对方线程this.notifyAll();}
}
/*** 生产者线程*   资源对象中的变量++*/
public class Produce implements Runnable{private Resource r ;public Produce(Resource r) {this.r = r;}@Overridepublic void run() {while (true) {r.setCount();}}
}
/*** 消费者线程*   资源对象中的变量输出打印*/
public class Customer implements Runnable{private Resource r ;public Customer(Resource r) {this.r = r;}@Overridepublic void run() {while (true) {r.getCount();}}
}
    public static void main(String[] args) {Resource r = new Resource();//接口实现类,生产的,消费的Produce produce = new Produce(r);Customer customer = new Customer(r);//创建线程new Thread(produce).start();new Thread(produce).start();new Thread(produce).start();new Thread(produce).start();new Thread(produce).start();new Thread(produce).start();new Thread(customer).start();new Thread(customer).start();new Thread(customer).start();new Thread(customer).start();new Thread(customer).start();new Thread(customer).start();}

1.2 线程方法sleep和wait的区别

  • sleep()在休眠的过程中,同步锁不会丢失 ,不释放

  • wait()等待的时候,发布监视器的所属权, 释放锁.唤醒后要重新获取锁,才能执行

1.3 生产者和消费者案例性能问题

wait()方法和notify()方法, 本地方法调用OS的功能,和操作系统交互,JVM找OS,把线程停止. 频繁等待与唤醒,导致JVM和OS交互的次数过多.

notifyAll()唤醒全部的线程,也浪费线程资源,为了一个线程,不得以唤醒的了全部的线程.

1.4 Lock接口深入

Lock接口替换了同步synchronized, 提供了更加灵活,性能更好的锁定操作

  • Lock接口中方法 : newCondition() 方法的返回值是接口 : Condition

1.5 生产者与消费者改进为Lock接口

  • Condition接口 (线程的阻塞队列)

    • 进入队列的线程,释放锁

    • 出去队列的线程,再次的获取锁

    • 接口的方法 : await() 线程释放锁,进入队列

    • 接口的方法 : signal() 线程出去队列,再次获取锁

线程的阻塞队列,依赖Lock接口创建

/***  改进为高性能的Lock接口和线程的阻塞队列*/
public class Resource {private int count ;private boolean flag ;private Lock lock = new ReentrantLock();//Lock接口实现类对象//Lock接口锁,创建出2个线程的阻塞队列private Condition prod = lock.newCondition();//生产者线程阻塞队列private Condition cust = lock.newCondition();//消费者线程阻塞队列//消费者调用public  void getCount() {lock.lock();//获取锁//flag是false,消费完成,等待生产while (!flag)//无限等待,消费线程等待,执行到这里的线程,释放锁,进入到消费者的阻塞队列try{cust.await();}catch (Exception ex){}System.out.println("消费第"+count);//修改标志位,为消费完成flag = false;//唤醒生产线程队列中的一个prod.signal();lock.unlock();//释放锁}//生产者调用public  void setCount() {lock.lock();//获取锁//flag是true,生产完成,等待消费while (flag)//无限等待,释放锁,进入到生产线程队列try{prod.await();}catch (Exception ex){}count++;System.out.println("生产第"+count+"个");//修改标志位,为生产完成flag = true;//唤醒消费者线程阻塞队列中年的一个cust.signal();lock.unlock();//释放锁}
}

1.6 Lock锁的实现原理

使用技术不开源,技术的名称叫做轻量级锁

使用的是CAS锁 (Compare And Swap) 自旋锁

JDK限制 : 当竞争的线程大于等于10,或者单个线程自旋超过10次的时候

JDK强制CAS锁取消.升级为重量级锁 (OS锁定CPU和内存的通信总线,只有一个线程通过)

2. 单例设计模式

设计模式 : 不是技术,是以前的人开发人员,为了解决某些问题实现的写代码的经验.

所有的设计模式核心的技术,就是面向对象.

Java的设计模式有23种,分为3个类别,创建型,行为型,功能型

 (此博客中单例模式)

Java-设计模式-(三)单例模式(创建型模式)_YounG_tt33的博客-CSDN博客

2.3 关键字volatile

成员变量修饰符,不能修饰其它内容

  • 关键字作用 :

    • 保证被修饰的变量,在线程中的可见性

    • 防止指令重排序

      • 单例的模式, 使用了关键字,不使用关键字,可能线程会拿到一个尚未初始化完成看的对象(半初始化)

3. 线程池ThreadPool

线程的缓冲池,目的就是提高效率. new Thread().start() ,线程是内存中的一个独立的方法栈区,JVM没有能力开辟内存空间,和OS交互.     (缓冲池技术)

JDK5开始内置线程池      类比数据库连接池(Connection)

3.1 Executors

  • 静态方法static newFixedThreadPool(int 线程的个数)  输入int后创建线程池固定,扩容则会创建新的线程池

    • 方法的返回值ExecutorService接口的实现类,管理池子里面的线程

  • ExecutorService接口的方法

    • submit (Runnable r)提交线程执行的任务

3.2 Callable接口

实现多线程的程序 : 接口特点是有返回值,可以抛出异常 (Runnable没有)

抽象的方法只有一个, call

启动线程,线程调用重写方法call

  • ExecutorService接口的方法

    • submit (Callable c)提交线程执行的任务

    • Future submit()方法提交线程任务后,方法有个返回值 Future接口类型

    • Future接口,获取到线程执行后的返回值结果 

public class MyRunnable implements Runnable {@Overridepublic void run() throws Exception{sout("线程开始启动");}
}
public class MyCall implements Callable {public String call() throws Exception{return "返回字符串";}
}
    public static void main(String[] args) throws ExecutionException, InterruptedException {//创建线程池,线程的个数是2个ExecutorService  es =  Executors.newFixedThreadPool(2);//线程池管理对象service,调用方法啊submit提交线程的任务MyRunnable my = new MyRunnable();//提交线程任务,使用Callable接口实现类Future future = es.submit(new MyCall());//返回接口类型 Future//接口的方法get,获取线程的返回值String str = future.get();System.out.println("str = " + str);//        es.submit(my);
//        es.submit(my);
//        es.submit(my);// es.shutdown();//销毁线程池}

4. ConcurrentHashMap

ConcurrentHashMap类本质上Map集合,键值对的集合.使用方式和HashMap没有区别.

凡是对于此Map集合的操作,不去修改里面的元素,不会锁定

5. 线程的6种状态图-生命周期

在某一个时刻,线程只能处于其中的一种状态. 这种线程的状态反应的是JVM中的线程状态和OS无关.

 

TIMED_WAITING:sleep()与wait():sleep()不释放锁,时间结束后继续执行;wait()会释放锁,时间结束后wait()若拿不到锁会转为阻塞状态BLOCKED。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...