一、java多线程基础

多线程的概念

进程是程序运行的实例。启动一个java程序其实就是启动了一个jvm的进程。进程是程序向操作系统申请资源(内存空间、文件句柄等)的基本单位。

线程是进程中可以独立执行的最小单位。

进程和线程的关系,可以比喻成一个项目组和组员的关系。项目组完成一个项目需要需求,开发,测试。这些往往都是并行的。需要需求,开发和测试人员协作完成。他们共享项目组的资源,如需求文档,功能代码等。

为什么需要线程

  1. 提高cpu的利用率。因为cpu的执行速率是远远高于io操作的。如果单线程运行,遇到io操作,系统会一直等待io完成再往下执行。这段io操作的时间内浪费了cpu的性能。
  2. 提高响应速率。为了用户的体验,在使用GUI软件时,一个慢的IO操作不至于会使软件"冻住"。
  3. 充分利用多核。对应已经普及的多核计算机,多线程可以重复利用其性能。

java中的线程

java中的线程是通过java.lang.Thread类来实现。一个Thread或其子类就是一个线程。

创建线程

创建执行线程的方式有三种:

Thread类的构造函数大概可以分为要Runnable和不需要Runnable两种。 Thread()和 Thread(Runnable)。所以可以根据这两种方式来创建一个线程。

  1. 继承Thread
    //1.继承Thread类
    class ThreadDemo extends Thread{
		
        //2.重写run方法。
		public void run() {
			// 业务逻辑
		}
	}
	
	public static void main(String[] args) {
        //new 一个Thread对象
		Thread thread = new ThreadDemo();
        //调用start方法启动一个线程。线程启动后会执行run方法。
		thread.start();
	}

  1. 实现Runnable接口
    //1.实现Runnable类
    class RunnableDemo implements Runnable{
        //2.实现run方法
		public void run() {
			// 业务逻辑
		}
		
	}
	
	public static void main(String[] args) {
	    //new 一Runnable实现类
		Runnable run  = new RunnableDemo();
		//通过Runnable构造Thread
		Thread thread2 = new Thread(run);
		//启动线程
		thread2.start();
	}

上面两种线程都没有返回值,jdk1.5后出现了callable能创建具有返回值的线程。

    //实现Callable接口
    class CallableDemo implements Callable<String>{
        //实现call方法
		public String call() throws Exception {
			return "callable";
		}
		
	}
	public static void main(String[] args) {
	
	//callable有两种使用方式:
	
	//1.通过线程池
	    //创建线程池
    	ExecutorService threadService = Executors.newSingleThreadExecutor();
    	//提交callable任务
		Future<String> submit = threadService.submit(new CallableDemo());
		//阻塞获取返回值
		String object = submit.get();
		System.out.println(object);
		
	//2. 通过FutureTask
	  FutureTask<String> task1 = new FutureTask<String>(new CallableDemo() {
		});
      Thread thread1 = new Thread(task1);
      thread1.start();
      System.out.println(task1.get());
    }

三种创建线程方式的差异

callable和runnable除了callable可以有返回值,其他的都一样。实际上callable最终会被构造成一个实现Runnable结构的类。例如上面的FutureTask。

主要分析Runnable方式和继承Thread这两种方式。

  1. 继承Thread是通过继承的方式,实现Runnable是一种组合的方式。组合相对于继承更加低耦合和灵活。《Effictive java》中也提到复合优先于继承的观点。

  2. 实现Runnable的方式,容易线程间实现资源的共享。因为一个Runnable对象可以用来创建多个线程。对象的成员变量被多个线程共享。这也使得我们要注意线程安全问题。

线程的属性

属性 作用
编号(ID) 用于标识不同线程
名称(Name) 用于区分不同线程 默认:"thread-0" .可以设置。
线程类别(Daemon) 可以设置守护线程。主线程结束,守护线程也会结束
优先级(Priority) 可以设置线程优先级,1-10.默认5.

线程的状态

借图: image

状态 说明
创建(New) 线程被创建未启动。java中就是还没调用start方法之前
可运行(Runnable) 该状态下有两种情况,一种是获取到cpu的时间片
阻塞(BLOCKED) 发起阻塞IO或者争取独占锁资源。该状态不占用cpu
等待(Waiting) 执行特定的方法会,等待其他线程唤醒
有时限等待(Timed Waiting) 和Waiting状态类似,但是Timed Waiting是有时限的,指定时间到会结束等待状态
消亡(Terminated) run方法执行完毕或者发生异常。

猜你喜欢

转载自blog.csdn.net/qq_26680031/article/details/81410867