多线程

目的

为什么在Java中要使用多线程
Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
进程和线程的区别
进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)
线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)。
多进程是指操作系统能同时运行多个任务(程序)。
多线程是指在同一程序中有多个顺序流在执行。

如何创建一个线程

我们如何在一个程序里面创建一个多线程呢?
我们学习了两种方法来创建一个线程
一、继承Thread类创建线程类
下面就是如何使用这个方法的步骤:
• 定义一个继承Thread类的子类,并重写该类的run()方法;
• 创建Thread子类的实例,即创建了线程对象;
• 调用该线程对象的start()方法启动线程。
代码示例:

class ThreadDemo extends Thread {
    @Override
    public void run(){
        String name=Thread.currentThread().getName();
        for(int i=0;i<100;i++){
            System.out.println(name+":"+(i+1));
            if(this!=MyClass.tt2){
                try{
                    MyClass.tt2.join();
                }
                catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
        super.run();
    }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.setName("子线程1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.setName("子线程2");
      T2.start();
   }   
}

二、实现Runnable接口创建线程类
通过实现Runnable接口创建线程类的具体步骤
• 定义Runnable接口的实现类,并重写该接口的run()方法;
• 创建Runnable实现类的实例,并以此实例作为Thread的target对象,即该Thread对象才是真正的线程对象。

class Demo implements Runnable {
    @Override
    public void run(){
        String name=Thread.currentThread().getName();
        for(int i=0;i<100;i++){
            System.out.println(name+":"+(i+1));
            if(this!=MyClass.tt2){
                try{
                    MyClass.tt2.join();
                }
                catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
        super.run();
    }
}
 
public class TestThread {
 
   public static void main(String args[]) {

      Demo R1 = new Demo();
      Thread onTread2 = new Thread(Demo); 
      onTread1.setName("子线程1");
      onTread1.start();

      Demo R2 = new Demo();     
      Thread onTread2= new Thread(Demo); 
      onTread2.setName("子线程2");
      onTread2.start();
   }   
}

一个线程的生命周期

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。
线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。
下图显示了一个线程完整的生命周期。

线程的轮回

新建状态:
使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
就绪状态:
当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
运行状态:
处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
1、如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。
2、如果该线程失去了cpu资源,就会又从运行状态变为就绪状态。重新等待系统分配资源。也可以对在运行状态的线程调用yield()方法,它就会让出cpu资源,再次变为就绪状态。

注: 当发生如下情况是,线程会从运行状态变为阻塞状态:
①、线程调用sleep方法主动放弃所占用的系统资源
②、线程调用一个阻塞式IO方法,在该方法返回之前,该线程被阻塞
③、线程试图获得一个同步监视器,但更改同步监视器正被其他线程所持有
④、线程在等待某个通知(notify)
⑤、程序调用了线程的suspend方法将线程挂起。不过该方法容易导致死锁,所以程序应该尽量避免使用该方法。

当线程的run()方法执行完,或者被强制性地终止,例如出现异常,或者调用了stop()、desyory()方法等等,就会从运行状态转变为死亡状态。
阻塞状态:
如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
死亡状态:
一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

Thread类的一些重要方法:

序号 方法描述
1 public void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
2 public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
3 public final void setName(String name) 改变线程名称,使之与参数 name 相同。
4 public final void setPriority(int priority) 更改线程的优先级。
5 public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。
6 public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。
7 public void interrupt() 中断线程。
8 public final boolean isAlive() 测试线程是否处于活动状态。

测试线程是否处于活动状态。 上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。

序号 方法描述
1 public static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
2 public static void sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
3 public static boolean holdsLock(Object x) 当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。
4 public static Thread currentThread() 返回对当前正在执行的线程对象的引用。
5 public static void dumpStack() 将当前线程的堆栈跟踪打印至标准错误流。

全篇wan

你可能感兴趣的:(多线程)