20200415_多线程——重点是应用场景
进程&线程
【1】一个程序会产生一个进程
【2】一个进程当中,可以有若个线程
【3】线程的执行,是在CPU当中进行高速的资源切换
【4】线程的执行、等待的时间,通常和CPU的运行性能和CPU的内核数有必然关系
线程创建方式
【1】对Thread类进行派生并覆盖run()方法
【2】通过实现Runnable接口创建
JVM
【1】主线程:在Java当中,main()方法。
【2】子线程:每创建一个线程,就会产生一个新的调用栈。
【3】用户线程:在执行过程当中,虚拟机不关闭
【4】守护线程:当某个程序的用户线程全部执行完毕后,守护线程立刻停止
线程实例化
【1】new Thread() new Thread(naeme) new Thread(new MyRunnable())
【2】start()方法,线程执行。
【3】Thread.currentThread().getName()
【4】start()方法启动线程之后,线程进入到预备执行状态。等待CPU分配资源,只有资源分配到了,才开始执行。
【5】run()方法只是一个普通的方法调用。
【6】sleep()、join() ---> otherwise blocked
【7】wait() ---> blocked in wait poll
【8】synchronized ---> blocked in lock poll
【9】 wait poll ----> notify() ---->lock poll ; blocked ----> sleep时间到 &&& 获得锁 ---->runnable 【只要是阻塞状态一定会回到可执行状态】;
【10】线程执行的(瞬时状态)——顺序是不可控的。
线程使用
【1】start()只能被调用一次,调用两次以上就会报错。
【2】尽管采用线程队列,但是依旧无法控制线程调度程序。
【3】线程和线程之间是相互独立的,各自有对应的栈空间——数据区。
【4】线程调度
-等待和唤醒:必须在同步状态下,给某个方法加同步锁,保证该方法。
-必须在同步状态下,才能 wait()
-this.wait():对象执行该方法
-等待可以被唤醒。this.notify(),也可以自己结束 this.wait(1000)[设置等待时间]。
-线程传参
-interrupt?????——应用场景?没见过
【5】线程等待生命周期
-获得锁,等待,释放资源(即释放锁);
-被唤醒\等待时间到,等待获取资源(获取锁),获取锁进入可执行状态
-只能是同一个对象进行等待、唤醒
【6】休眠
-不可被唤醒,只能自己醒
-休眠,阻塞,时间到,可执行状态执行
【7】让步与优先级:threa.setPriority(1~10)
-Thread.MAX_PRIORITY
-Thread.MIN_PRIORITY
-让步,可执行状态,执行。yield(),不能保障太多,基本不用。
【8】合并
-线程原本是并行的,合并后,线程变成串行。
-合并的线程,可以在指定时间后,自动开始执行。
-与sleep()机制一致:生命周期一致
-线程start()后,才能 join()
【9】守护线程
-区别于【1-8的】用户线程
-thread.setDaemon(true);——设置为守护线程
-用户线程结束,守护线程立刻结束
i++:分三步操作,不是原子性操作。{读、改、写}
思考点:多线程读取三体多集,分别初步处理。然后合并,MR处理。
0417——同步与锁
多线程的问题:
【1】对相同数据的并发操作:获取 查看 【修改 赋值】
【2】但是无论多少线程并发,如果只是查看数据,那么该行为不会产生影响。
----synchronized——同步
【3】线程同步:让某个方法在并发的情况下,依次排队执行。同一时刻,只有一个线程,拥有该方法或者代码块的锁,称:持锁。
【4】Java中每个对象都有一个内置锁。
【5】只能同步方法、代码块,不支持变量、类。
-------同步锁的影响
【1】同步锁会对多项成情况下的程序执行效率降低。
【2】不存在类的同步、属性的同步。
【3】sleep(),不会释放锁。
【4】synchronized(this){【会受到并发影响的代码块通通包裹起来】} –同步代码块;读数据不受并发影响---保障同步代码块之外的其他数据不受影响!
【5】同步代码块zhi前可以做一些具有共享的操作,或者不影响数据的操作:同步代码块之后的内容,会受到同步等待的影响。
【6】同一段代码块,如果锁的对象不同,同步不生效。当且仅当锁同一个对象,并发生效。
【7】一个线程可以同时持有多个对象的锁。同时拥有多个对象锁的情况下,有可能会产生死锁。虽然这个概率极低。——但是只要有这种可能性存在,那么就必须考虑周全!
-----静态方法的同步
【1】synchronized(A.class){}——同步是class
【2】静态代码块的同步,A.test()_静态方法的同步
con:
【1】静态与非静态同步方法永远不会阻塞。
【2】多项成同时访问互斥数据是,同步保护数组。
【3】非静态、静态同步最好不要混用![减少嵌套]——主要原因是:很难控制,除非对底层及整个机制熟稔
【4】即便是线程安全的类,在并发情况下,会受到其他变量或者非同步方法的影响,从而对数据安全造成隐患。——操作线程安全类的逻辑本身不安全。——通过对整个操作逻辑进行加锁实现安全。
【5】原子化操作。
-------volatile
【1】可见性:确保释放锁之前对共享数据做出的更改,对于随后获得该锁的另一个线程是可见的。
【2】Volatile:不能保障数据安全。
【3】实现数据安全:1,把读和写分开。
【4】volatile 不能用于 final对象。
【5】JavaBean当中,属性可以加Volatile修饰,然后给set方法加同步。
-------可见性适合一个线程写,多个线程读项目中单例我就加了volatile
excludes:
缓存(cache)是在读取硬盘中的数据时,把最常用的数据保存在内存的缓存区中,再次读取该数据时,就不去硬盘中读取了,而在缓存中读取。
缓冲(buffer)是在向硬盘写入数据时,先把数据放入缓冲区,然后再一起向硬盘写入,把分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能。
简单来说,缓存(cache)是用来加速数据从硬盘中"读取"的,而缓冲(buffer)是用来加速数据"写入"硬盘的。=============
Scanner next()&&nextLine()方法区别
-Scanner是一个扫描器,我们录取到键盘的数据,先存到缓存区等待读取,它判断读取结束的标示是 空白符;比如空格,回车,tab 等等。
-next()方法读取到空白符就结束l;
-nextLine()读取到回车结束也就是“\r”;