发表于: 2017-11-03 19:55:11

0 880


今日完成:

 

      按照昨日计划,先补以前欠缺的基础

 

先是多线程

 

了解前,先知道什么是进程,通俗的说就是正在运行的程序,但是理论上进程指的是我们的应用程序在我们的内存中分配的空间

 

那么线程就是负责程序执行的执行单元,也称为执行路径,一个进程中最少最少有一个线程来负责该进程的运行,so 一个进程中出现了多个线程就就称该程序为多线程程序,比如我们在使用360安全卫士时可以同时进行杀毒 体检  和清理3个功能

 




多线程技术解决的是多部分代码同时执行的需求,合理的利用CPU资源,并不是提高效率!


这里解释一下,在进程中执行的每一条线程最后都会使用我们电脑最核心的CPU来进行运算,但是每一个CPU核心在一个时间片段内只能执行1条线程的运行处理,那么就很奇怪了,我们所谓的多线程是如何同时进行的呢?这是因为CPU会非常非常快速的切换线程计算,也就是执行这个线程一会儿,再切换另一个线程再执行一会儿,从而我们会在表面看到所谓的同时进行的效果.当我们的线程量变的很大的时候,CPU就会忙不过来了,从而会出现假死的一种死机状态,这是因为前面排队等待的线程太多了,CPU要一个个切换处理,当前线程执行的等待时间就会很长.

但是现在技术发展了,我们有双核48核的CPU,能做到真正的同时进行线程,从之前的单个CPU最多能处理50个线程,到现在多核(打个比方具体我也不清楚)1000条线程,比如电脑只运行了300条线程,那么剩余的资源为什么不合理利用了呢?所以这个就是我上面说的合理利用CPU资源了!

 

在我们的JAVA虚拟机JVM,最少存在着2条线程,一是我们的主程序,二是我们的垃圾回收线程


在JAVA中实现多线程

   第一是继承Thread的类

     重写run方法

     创建子类对象就是创建线程对象

     调用Thread类中的start方法就可以执行线程,并调用上面重写run方法


start开启线程后,都会执行run方法,说run方法中存储的是线程要运行的代码,所以自定义线程的任务代码全部在run方法中,测试下!


start方法会做两件事①开启当前线程②执行run方法

数据呈现出交替打印,执行效果达到!





在JAVA中实现多线程

   第二是实现Runnable接口

   重写run方法,将想要运行的任务放到该方法中

   创建Thread类线程对象,将我们实现了Runnable接口的类作为参数传入Thread中

   调用Thread.start()方法启动线程



两种方法相互比较,推荐使用第二种方法!

①实现Runnable接口,避免了继承Thread类的单继承的局限性

②Runnable接口更加符合面向对象,将线程任务进行单独的封装

③Runnable接口的出现,降低了线程对象和线程任务的耦合性



                                                     下图是线程的运行状态图






但是多线程的同时会带来安全问题,因为线程数太少看不出来,这里使用sleep()放大演示一下

代码修改如下,在每次进入方法后沉睡1毫秒

结果显示


这里的0是怎么来的呢?


当最后线程1 进入run方法时,进行沉睡1毫秒时,线程2也进入了该方法,那么当线程1进行打印数字1,并自减一次后,我们的i等于0了,这个时候线程2沉睡后开始执行下一步打印数字,这个时候0就被打印出来了,这个时候再自减一次i变为了-1,此时就存在着安全风险.


如何解决呢?

使用synchronized关键词表示当前 方法执行为 同步,也就是说每当一个线程进入该标识内的方法时,该方法对外关闭,其他线程无法同时进入,必须等到该线程执行完毕之后才会进入方法进行操作.

但这里需要对该方法传一个参数,表示持有该锁住的对象,但是这里要注意了如果持有的琐对象是不同的锁,依旧无效.

这里synchronized传入的参数每次都是一个新的Object,来试下锁对象不同的效果


这里结果依旧存在着0,说明我们使用的同步方法并没有生效



修改如下

测试结果,满足条件




这里同步方法存在着2种方式

第一种就是上方的同步代码块就是

synchronized(锁对象){

   .........

   运行的内容

   .........

}


第二种就是同步函数synchronized 用来修饰方法名称!

先不加修饰符函数如下


调用测试函数及结果,同时打印了2个200


加上修饰符

测试结果OK!


这里引发思考,当我使用第一种synchronized 代码块时,我需要使用锁对象,但是这里使用同步函数时,这个锁对象往哪儿去了呢?

其实这里的锁对象是当前调用add方法时所对应的对象,就是this!


那么问题又来了当我的方法为静态方法时,锁对象是谁?因为静态随着类的加载,它还没有类的产生所以this根本就无法使用,而真正的锁对象是当前对象的字节码对象!也就是xxx.class,这里看的时候还是太晦涩了...






当我们使用同步代码块发生嵌套时,非常容易发生一件很恐怖的事,就是死锁.也就是当线程1拿到锁对象A后执行一下句准备拿锁对象B,而此时线程2执行拿取锁对象B执行下一步准备拿锁对象A,这时程序有非常高的可能性被挂在那线程1拿不到锁对象B,线程2拿不到锁对象A,两条线程就互相等待着对方释放锁...



写个代码演示下



测试代码如下,在循环执行4句后,死锁成功锁住了当前程序,两条线程都处于等待挂起状态,且不会出现任何的报错!




明日计划:复盘项目已定下来,明天准备动手,IO流是我JAVA心中的通,一定要抽空整完!


问题:无


收获:好好把多线程复习了一遍


返回列表 返回列表
评论

    分享到