java多线程

1.进程和线程的区别:

    每个正在系统上运行的程序都是一个进程。每个进程包含一到多个线程。线程是一组指令的集合,或者是程序的特殊段,它可以在程序里独立执行。也可以把它理解为代码运行的上下文。所以线程基本上是轻量级的进程,它负责在单个程序里执行多任务。通常由操作系统负责多个线程的调度和执行。

   总结:进程是所有线程的集合,每一个线程是进程中的一条执行路径。

 

2.为什么要使用多线程

 案例:如果一个工人修建一条1000米长的铁路需要10个小时,为了尽快完成工期,需要在一个小时内完成所有的铁路修建,如何解决呢?

此时可以在加派9个工人,最后就是10个工人一起修建(考虑每个工人的修建速度一样)则只需要1个小时就可以完成.

同样:使用多线程可以提高程序的效率.

 

3.在java中如何创建多线程

  1.继承Thread类,重写run方法

package com.thread;

public class ThreadDemo extends Thread {
    @Override
    public void run() {
        System.out.println("继承Thread重写run方法");
    }

    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        threadDemo.start();
    }
}

 

输出:继承Thread重写run方法

注意:启动一个线程是用的.start()方法 而不是直接调用的run方法,如果直接调用run方法只是实例化的一个方法调用,根本没有启动一个线程

思考:开启一个线程以后,该线程和main方法的执行先后顺序?

 

package com.thread;

public class ThreadDemo extends Thread {
    @Override
    public void run() {
        System.out.println("继承Thread重写run方法");
    }

    public static void main(String[] args) {
        System.out.println("main方法开始运行");
        ThreadDemo threadDemo = new ThreadDemo();
        threadDemo.start();
        System.out.println("main方法结束");
    }
}

输出结果:

main方法开始运行
main方法结束
继承Thread重写run方法

从输出结果可以看出,主程序的运行结束与否和新创建的线程运行情况无关,即使主线程运行完成,此时可能用户线程还在运行,不会随着主线程消亡而结束(守护线程则会)

 

 2.实现Runnable接口的方法

  

package com.thread;

public class RunnableDemo implements Runnable {
    public void run() {
        System.out.println("实现Runnable接口重写run方法");
    }

    public static void main(String[] args) {
        RunnableDemo runnableDemo = new RunnableDemo();
        Thread thread = new Thread(runnableDemo);
        thread.start();
    }
}

输出结果:

实现Runnable接口重写run方法

 

 3.使用匿名内部类的方法创建多线程

 public static void main(String[] args) {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("匿名内部类的方法创建线程运行run方法");
            }
        }).start();

    }

 

4.使用Callabel接口创建一个具有返回值的线程

package com.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class CallableThreadDemo implements Callable<String> {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableThreadDemo callableThreadDemo = new CallableThreadDemo();
        FutureTask<Integer> futureTask = new FutureTask(callableThreadDemo);
        new Thread(futureTask, "有返回值的线程").start();
        System.out.println(futureTask.get());
    }

    public String call() throws Exception {
        return "我是线程 Callable接口的返回值哟";
    }


}

输出结果:

我是线程 Callable接口的返回值哟

 

5.使用线程池创建线程(后续补充)

 

 

4. 在创建线程的时候使用Thread继承好还是使用Runnable接口好

答:使用接口好,接口可以多继承

 

5.常用的线程API

  1.获取当前线程对象的方法:currentThread()

  2.启动线程:.start()

  3.休眠线程:sleep(时间)cpu执行其他线程,但是不会释放当前线程已经拥有的锁

  4.停止线程:stop()

6.线程的分类

 线程分成两类

  1.用户自定义线程:该线程不会随着主线程死亡而死亡,可以理解成main方法执行完毕以后,自定义线程还在执行

  2.守护线程:主线程执行完毕以后守护线程就自动死亡,可以通过thread.setDaemon(true)将该线程设置为守护线程

 

7.线程的状态(重点)

  1.新建状态:new Thread()表示一个线程的创建,但是此时线程还并没有开始执行

 2.就绪状态:当前线程调用start()的时候 表示线程已经就绪,此时等待cpu调度

 3.运行状态:如果当前线程获取到了cpu的执行权,则开始运行该程序(执行run方法)

 4.死亡状态:run方法正常的执行完毕,或者run方法里面执行错误,该错误没有被捕获也会导致线程死亡(和main方法一样如果程序出错,没有捕获异常,则程序不会继续执行)

 5.阻塞状态:导致线程阻塞的情况有很多场景:比如调用sleep()方法,在同步锁当中执行一个方法的时候,没有获取到该方法的锁也会阻塞。如果操作数据库的时候IO时间较长,该线程也会阻塞  在调用sleep()方法以后,休眠时间到了,重新获取到cpu的执行权,则该线程又进入到运行状态

 

8.设置线程的优先级和如何让多个线程优先执行一个线程

 优先级:现代操作系统基本采用时分的形式调度运行的线程,线程分配得到的时间片的多少决定了线程使用处理器资源的多少,也对应了线程优先级这个概念。在JAVA线程中,通过一个int priority来控制优先级,范围为1-10,其中10最高,默认值为5。可以通过 Thread.setPriority设置线程的优先级,设置优先级并不是每次都执行这个线程,只是会优先于这个线程

 顺序性:如果有三个线程,你先让线程2先执行,执行完成以后 在执行线程1,最后在执行线程3 使用join

 

package com.thread;

public class ThreadDemo extends Thread {
    @Override
    public void run() {
        String name = currentThread().getName();
        System.out.println(name + "继承Thread重写run方法");
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadDemo threadDemo1 = new ThreadDemo();
        threadDemo1.setName("线程1");
        ThreadDemo threadDemo2 = new ThreadDemo();
        threadDemo2.setName("线程2");
        ThreadDemo threadDemo3 = new ThreadDemo();
        threadDemo3.setName("线程3");
        threadDemo2.start();
        threadDemo2.join();
        threadDemo1.start();
        threadDemo1.join();
        threadDemo3.start();

    }
}

输出结果:

线程2继承Thread重写run方法
线程1继承Thread重写run方法
线程3继承Thread重写run方法

 

 

posted on 2019-08-12 18:49  年少不知愁  阅读(303)  评论(0编辑  收藏  举报