四十三、多线程

1、线程相关概念

并发: 在同一时刻,有多个任务在多个CPU上同时执行。

并行: 在同一时刻,有多个任务在单个CPU上交替执行。

进程: 进程简单地说就是在多任务操作系统中,每一个单独执行的程序

线程: 线程是程序运行的基本执行单元; 也就是应用程序中做的事情

多线程:

  • 是指从软件或者硬件上实现多个线程并发执行的技术
  • 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。

2、Thread类

线程开启我们需要用到了java.lang.Thread类,API中该类中定义了有关线程的一些方法,具体如下:

2.1 构造方法

方法 描述
public Thread() 分配一个新的线程对象。
public Thread(String name) 分配一个指定名字的新的线程对象。
public Thread(Runnable target) 分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) 分配一个带有指定目标新的线程对象并指定名字

2.2 常用方法

方法 描述
public String getName() 获取当前线程名称。
public void setName(String name) 修改线程名字
public void start() 导致此线程开始执行; Java虚拟机调用此线程的run方法。创建了一个新的线程
public void run() 此线程要执行的任务在此处定义代码.
public static Thread currentThread() 返回对当前正在执行的线程对象的引用。
public static void sleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。是当代码执行到所在位置时进行休眠
public void join() 具备阻塞作用,等待这个线程死亡,才会执行其他线程; 放在 start方法 的后面
public final void setPriority(int newPriority) 设置线程的优先级
public final int getPriority() 获取线程的优先级

3、创建线程方式一:继承Thread

Java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。每个线程的作用是完成一定的任务,实际上就是执行一段程序流即一段顺序执行的代码。Java使用线程执行体来代表这段程序流。

创建使用:

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
  2. 创建Thread子类的实例,即创建了线程对象
  3. 调用线程对象的start()方法来启动该线程

代码体现:

【测试类】
public class Demo01 {
	public static void main(String[] args) {
		//创建自定义线程对象
		MyThread mt = new MyThread("新的线程!");
		//开启新线程
		mt.start();
		//在主方法中执行for循环
		for (int i = 0; i < 200; i++) {
			System.out.println("main线程!"+i);
		}
	}
}

【自定义线程类】
public class MyThread extends Thread {
	//定义指定线程名称的构造方法
	public MyThread(String name) {
		//调用父类的String参数的构造方法,指定线程的名称
		super(name);
	}
  	public MyThread() {
		//不指定线程的名字,线程有默认的名字Thread-0
	}
	/**
	 * 重写run方法,完成该线程执行的逻辑
	 */
	@Override
	public void run() {
		for (int i = 0; i < 200; i++) {
			System.out.println(getName()+":正在执行!"+i);
		}
	}
}    

可以使用匿名内部类

4、创建线程方式二:实现Runnable

采用java.lang.Runnable也是非常常见的一种,我们只需要重写run方法即可。

创建使用:

  1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
  3. 调用线程对象的start()方法来启动线程。

代码体现:

【测试类】
public class Demo {
    public static void main(String[] args) {
        //创建自定义类对象  线程任务对象
        MyRunnable mr = new MyRunnable();
        //创建线程对象
        Thread t = new Thread(mr, "小强");
        t.start();
        for (int i = 0; i < 20; i++) {
            System.out.println("旺财 " + i);
        }
    }
}

【自定义线程类】
public class MyRunnable implements Runnable{
	@Override
	public void run() {
		for (int i = 0; i < 20; i++) {
			System.out.println(Thread.currentThread().getName()+" "+i);
		}
	}
}

可以使用匿名内部类

5、创建线程方式三:实现Callable接口

【测试类】
public class MyThread03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        Thread.currentThread().setName("主线程");

        // 创建Callable的实现类对象
        MyCallable myCallable = new MyCallable();
        // 中间者 , 作为Thread类和Callable接口的桥梁
        FutureTask<String> task = new FutureTask<>(myCallable);
        Thread t1 = new Thread(task , "线程1");
        // 开启线程
        t1.start();

        // FutureTask类中存在一个get方法 , 可以获取call方法最后的返回值
        // get方法必须放在开启线程之后
        String s = task.get();// 具备阻塞作用!
        System.out.println(s);// "答应"

        // main线程中的任务
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

【自定义线程类】
// 1 自己写一个类实现Callable接口
class MyCallable implements Callable<String> {
    // 编写任务的方法
    // 此方法的返回值 , 是当前线程执行完毕,结果数据
    @Override
    public String call() throws Exception {
        for (int i = 1; i <= 100; i++) {
            System.out.println("求爱" + i + "次!");
        }
        return "答应";
    }
}

6、三种方法的区别

1 继承Thread
    优点 : 编程比较简单,可以直接使用Thread类中的方法
    缺点 :
	1 可扩展性较差,不能再继承其他的类
    	2 任务方法run() , 没有返回值 , 不能抛出异常只能捕获异常

2 实现Runnable : 相对于使用较多!
    优点 : 扩展性强,实现该接口的同时还可以继承其他的类。
    缺点 :
	1 编程相对复杂,不能直接使用Thread类中的方法
    	2 任务方法run() , 没有返回值 , 不能抛出异常只能捕获异常

3 实现Callable
    优点 :
	1 扩展性强,实现该接口的同时还可以继承其他的类。
    	2 当任务执行完之后,可以返回一个结果值
    	3 call方法中如果出现了异常既可以抛出也可以捕获
    缺点 :
	1 编程相对复杂
posted @ 2021-07-04 15:55  火烧云Z  阅读(43)  评论(0)    收藏  举报