多线程总结1
一、对多线程的理解
1.进程和线程
程序是指令和数据的有序集合,本身没有任何运行的含义,是一个静态的概念。几乎所有的操作系统都支持同时运行多个任务,一个任务通常就是一个程序,每个运行中的程序就是一个进程。当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程。一个程序只有一个进程,但一个进程可以有多个线程。
进程:正在进行中的程序。其实进程就是一个应用程序运行时的内存分配空间。
线程:程序的执行路径。程序只有一条执行路径就是单线程;程序有多条执行路径就是多线程。
2.理解并发与并行
思考:我们在一边玩游戏,一边带上耳机听歌,请问玩游戏与听歌是同时进行的吗?
显然不是,因为CPU在某一个时间点上只能做一件事,我们玩游戏,CPU就切换到执行游戏进程,听歌,CPU就切换到听歌进程;CPU就这样反复做这高效率的切换动作,这种切换是随机的,但是让我们感觉到就是同时发生的,这就是并发的概念。
并发:通过CPU调度算法,让用户看上去同时执行,实际上,是通过CPU在高速切换,并不是真正的额同时。
并行:多个CPU实例或者多台机器同时执行一段处理逻辑,这就是真正的同时;
或这样表述==>
并发:指在同一时刻,只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果。
并行:指在同一时刻,有多条指令在多个处理器上同时执行;
3.多线程出现的原因(多线程的优点):
1)为了解决负载均衡问题,充分利用CPU资源;
2)为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不互相干扰;
3)防止阻塞。如果我们使用单线程执行一个任务,如果碰到I/O操作(或其他耗时操作),后面的任务就要被阻塞,这时候CPU就处于空闲状态。 如果是多线程的情况,就可以各自(交替)执行不同的操作,即使I/O阻塞,也不会影响另一个线程的运行;
4)可以把程序中比较耗时的任务放到后台去处理;
5)优化用户体验,比如迅雷使用多线程同时下载多个文件。
二、创建线程的三种方式
参考:https://www.cnblogs.com/colily/p/6690038.html和https://blog.csdn.net/u011240877/article/details/57202704
1)实现 Runnable 接口;
2)继承 Thread重写其 run 方法;
3)实现 Callable 接口重写 call 方法用 FutureTask 获得结果;这一种是带有返回值的。
三、线程的一些属性
1.优先级
Thread 有个优先级字段:private int priority,值从 1 到 10 逐渐提高,默认为 5。
线程的优先级可以在一定程度上影响它得到时间片的多少,也就是被处理的机会。有长耗时操作的线程,一般建议设置低优先级,确保处理器不会被独占太久; 频繁阻塞(休眠或者 I/O)的线程建议设置高优先级。
2.守护线程(后台线程)
Thread 中有个布尔值标识当前线程是否为守护线程:private boolean daemon = false;该属性需要在调用线程的 start() 方法之前调用。
四、线程控制(线程的一些常用的方法)
1.Thread.sleep(long millis)
使当前所在线程进入阻塞;只是让出 CPU,并没有释放对象锁;由于休眠时间结束后不一定会立即被 CPU 调度,因此线程休眠的时间可能大于传入参数;如果被中断会抛出 InterruptedException。
2.join():表示线程合并,需要等待被调用线程结束后才可以执行。
ThreadJoin tj1 = new ThreadJoin(); ThreadJoin tj2 = new ThreadJoin(); ThreadJoin tj3 = new ThreadJoin(); tj1.start(); try { tj1.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 等待线程tj1结束,才会执行线程tj2和tj3 tj2.start(); tj3.start();
3.Thread.yield():暂停当前正在执行的线程对象。和 sleep() 方法不同的是,它不会进入到阻塞状态,而是进入到就绪状态。
4.setDaemon(boolean on):将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程(也叫后台线程)时,Java 虚拟机退出。 该方法必须在启动线程前调用。
5.interrupt():中断线程。
五、什么是线程安全,如何保证线程安全
1.线程安全
1)简单来说,线程安全就是: 在多线程环境中,能永远保证程序的正确性。
2)只有存在共享数据时才需要考虑线程安全问题。其中, 方法区和堆就是主要的线程共享区域。那么就是说共享对象只可能是类的属性域或静态域。
3)当一个类被多个线程进行访问并且正确运行,它就是线程安全的。
4)当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或者协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
2.判断是否有线程安全问题?
1)是否是多线程环境;2)是否有共享数据;3)是否有多条语句操作共享数据。
3.如何解决多线程安全问题:把多个语句操作共享数据的代码锁起来,让任意时刻只能有一个线程执行。(多线程同步机制)
六、线程同步
1)7种同步方式:参考 https://www.cnblogs.com/XHJT/p/3897440.html
2)同步代码块的锁对象:任意对象
3)同步方法的锁对象:this
4)同步静态方法的锁对象:类的字节码文件对象(类.class)
七、同步的弊端
1)效率低;2)可能产生死锁。
死锁:两个或两个以上的线程在争夺资源的过程中,发生相互等待的现象。(相互等待对方释放锁)
八、线程的状态
线程的5种状态:新建(New),就绪(Runnable),运行(Running),阻塞(Blocked),死亡(Dead)
线程的状态转换图:见我的另一篇博客。
posted on 2019-03-03 15:12 wenbin_ouyang 阅读(126) 评论(0) 编辑 收藏 举报