木心

毕竟几人真得鹿,不知终日梦为鱼

导航

多线程总结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编辑  收藏  举报