多线程创建方式

212 阅读3分钟

一、多线程概念

  • 并行:同一时间段,无论从微观还是宏观,程序都是一起执行的。
  • 并发:同一时间段,两个或多个程序执行,有时间上的重叠。

进程

一段程序的执行过程。

进程有以下几个特征:

  • 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
  • 并发性:任何进程都可以同其他进程一起并发执行
  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
  • 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进

结构特征:进程由程序、数据和进程控制块三部分组成。

进程的状态: Ready(就绪状态)Running(运行状态)Blocked(阻塞状态)

线程:进程是操作系统分配资源的单位,线程是调度的基本单位,线程之间共享进程资源。 多线程:一个进程如果有多条执行路径,则称为多线程程序

二、多线程实现方式

继承Thread

  • 定义继承Thread类的MyThread
  • MyThread类中重写run方法
  • 定义测试类ThreadDemo
  • 创建线程,执行线程

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+"_"+i);
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread mt1 = new MyThread();
        MyThread mt2 = new MyThread();

        mt1.start();
        mt2.start();
    }
}

注意:

  • start():启动线程;然后由JVM调用此线程的run()方法
  • run():封装线程执行的代码,直接调用,相当于普通方法的调用

实现Runnable接口

  • 定义RunnableDemo实现Runnable接口
  • 重写Run方法
  • 创建RunnableTest类
  • 创建RunnableDemo对象
  • 创建Thread类的对象并将RunnableDemo对象作为参数传入Thread
  • 启动线程
public class RunnableDemo implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "_" + i);
        }
    }
}

public class RunnableTest {
    public static void main(String[] args) {
        // 创建参数的对象
        RunnableDemo rb1 = new RunnableDemo();
        // 创建线程对象并传递参数
        Thread t1 = new Thread(rb1);
        // 开启线程
        t1.start();

        RunnableDemo rb2 = new RunnableDemo();
        Thread t2 = new Thread(rb2);
        t2.start();
    }
}

实现Callable接口

  • 定义CallableDemo类实现Callable接口
  • 在CallableDemo类中重写call()方法
  • 创建CallableTest类对象
  • 创建FutureTask对象,并将CallableDemo对象作为参数传递进去
  • 创建Thread类对象,并将FutureTask对象作为参数传递进去
  • 启动线程,并通过get获取执行结果
public class CallableDemo implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "----" + i);
        }
        return "CallableDemo";
    }
}

public class CallableTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建CallableDemo对象
        CallableDemo cd = new CallableDemo();
        // 作为参数传递给Thread对象
        FutureTask<String> sft = new FutureTask<>(cd);
        //创建线程对象
        Thread thread = new Thread(sft);
        //开启线程
        thread.start();
        System.out.println(sft.get());
        
    }
}

总结

  • 继承Thread类: 编写简单,但扩展性差,不能在继承其他的类
  • Runnable与Callable: 扩展性强,还可以继承其他的类,但编写复杂,不能直接使用Thread

线程的修改

  • setName(String name): 修改线程名称为name
  • getName(): 获取该线程名称
  • currentThread():返回对当前正在执行的线程对象的引用
  • sleep(long millis):使当前正在执行的线程停留(暂停执行)指定的毫秒数

三、线程的优先级

线程有两种调度方式:

  • 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
  • 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些
  • Java使用的是抢占式调度模型

修改线程优先级

  • setPriority(int newPriority):更改此线程的优先级线程默认优先级是5;线程优先级的范围是1-10
  • getPriority():返回此线程的优先级
public class ThreadTest {
    public static void main(String[] args) {
        ThreadDemo mt1 = new ThreadDemo();
        ThreadDemo mt2 = new ThreadDemo();

        mt1.setName("线程1");
        mt1.setPriority(1);
        mt2.setName("线程2");
        mt2.setPriority(10);
        mt1.start();
        mt2.start();

    }
}

守护线程

  • setDaemon(boolean on):如果普通线程执行完毕,那么守护线程也就停止执行,java虚拟机退出
mt2.setDaemon(true);