java线程基础知识

来源:互联网 发布:ubuntu wine安装qq 编辑:程序博客网 时间:2024/05/22 08:17
  • 以下是本文的目录大纲:
    • 一、线程概念
    • 二、创建线程的两种方式
    • 三、线程的状态以及各状态之间的相互转换
    • 四、线程安全问题
    • 五、线程安全问题的解决方案
  • 线程:程序执行的最小单元。CPU在某一时间片内只能执行一个线程,这句话的简单解释就是计算机在N个线程之间做着快速的切换,具体哪个时刻切换到哪个线程,影响因素是多方面的,从线程本身来说是有优先级的,优先级越高,被执行的概率也会越大。这里是概率,并不是优先级最高一定最先执行。
  • 创建线程的两种方式:第一种:继承Thread类,重写里面的run方法;第二种:实现Runnable接口,实现里面的run方法;大家都应该去使用第二种方法,因为java只能单继承嘛,且从源码上来看Thread类也是实现了Runnable接口,但是开启一个线程通用代码都是:
    { Thread t = new 具体的继承类(); t.start();} 或者是
    { Thread t = new Thread(new 实现Runnable具体的线程类());t.start()}
    Thread.java中start()方法的源码如下:
public synchronized void start() {    // 如果线程不是"就绪状态",则抛出异常!threadStatus 是一个成员变量    if (threadStatus != 0)        throw new IllegalThreadStateException();    // 将线程添加到ThreadGroup中    group.add(this);    boolean started = false;    try {        // 通过start0()启动线程,start0()是本地方法        start0();        // 设置started标记        started = true;    } finally {        try {            if (!started) {                group.threadStartFailed(this);            }        } catch (Throwable ignore) {        }    }}
  • 线程的状态:线程包括新建(New)、运行(Running)、堵塞(Blocked)、可执行状态(Runnable)、死亡(Dead),五中状态的转换关系如下(OneNote画的,各位看官凑合看吧):
    这里写图片描述
  • 1.新建状态(New):
    • 当用new操作符创建一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。
  • 2.就绪状态(Runnable)
    • 一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
      处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。
  • 3.运行状态(Running)
    • 当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.
  • 4.阻塞状态(Blocked)
    • 线程运行过程中,可能由于各种原因进入阻塞状态:
      1>线程通过调用sleep/wait/yet等方法进入睡眠状态;
      2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
      3>线程试图得到一个锁,而该锁正被其他线程持有;
      4>线程在等待某个触发条件;
      ……
      所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。
  • 5.死亡状态(Dead)
    • 有两个原因会导致线程死亡:
      1) run方法正常退出而自然死亡;
      2) stop方法可让线程停止运行;
  • 线程安全问题:每次说到线程,安全这话题是绕不开的,之所以会有线程安全的问题,是因为存在某一个共享资源同时被多个线程访问,资源且有可能被修改才会产生安全问题。注意这里面有几个要素:1,共享资源;2,被多个线程访问;3,存在修改操作;如果存在t1(Thread)、t2两个线程,资源r(Resource),如果r只被t1所拥有则不存在安全问题,对r的操作完全是私有行为,且不会对其它的对象产生影响,所以就不存在安全问题,如果r是可以被t1、t2同时访问,但都是查看操作,不存在增、删、改,也是不会产生线程安全的问题。
  • 线程安全问题的解决:
    • 1),从根本上:也就是尽量不出现共享资源,不出现成员变量,即使出现,成员变量的状态也是固定不变的;
    • 2),使用锁控制(最常用):思路:就是将操作共享数据的线程代码封装起来,当有线程执行这些代码的时候,其他线程不可以参与运算。涉及到锁又会有以下几种方案:
      • a,同步代码块,使用sychronized关键字;
        例:sychronized(锁) { // 业务行为 }
      • b,同步函数:在方法前加上sychronized
        例:public sychronized void threadSafe() { //业务行为 }
      • c,Lock 锁,在java 1.5之后出现了Lock锁的使用,jdk文档解释:Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。锁是控制多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先获得锁。
    • 3),Blocked队列(某些情况下可用):在典型的生产者和消费者模型中,队列是不错的解决方案!
  • 关于生产者和消费者模型我会用三种方式另写一篇博客,谢谢大家!
1 0
原创粉丝点击