Java8——Java多线程实现

进程与线程:

Java是一门为数不多的多线程支持的语言;

线程是在进程基础上的一个划分,即一个进程可以创建多个线程;线程是比进程更快的处理单元;

如果进程消失了,那么线程一定会消失,但是如果线程消失了,进程不一定会消失;

多线程的实现:

Java中实现多线程有2种途径:

  • 继承Thread类
  • 实现Runnable接口(Callable接口);

继承Thread类:

Thread类是一个支持多线程的类,只要有一个子类就可以实现多线程的支持;

所有程序的起点是main()方法,线程的起点是run()方法,在多线程的每个主体类中必须覆写Thread类中所提供的run()方法;

范例:

class MyThread extends Thread {// 这就是一个多线程的操作类
	private String name;

	public MyThread(String name) {
		this.name = name;
	}

	@Override
	public void run() {// 覆写run()方法,作为线程的主题操作方法
		for (int x = 0; x < 200; x++) {
			System.out.println(this.name + "-->" + x);
		}
	}
}

public class test {// 主类
	public static void main(String args[]) {
		MyThread mt1 = new MyThread("线程A");
		MyThread mt2 = new MyThread("线程B");
		MyThread mt3 = new MyThread("线程C");

		mt1.run();
		mt2.run();
		mt3.run();
	}
}

本线程的功能是进行循环输出的操作,根据输出结果可以知道,三个线程依次执行,但是线程和进程一样,必须轮流抢占资源,所以run()方法并不能启动多线程;所以启动多线程的方法是Thread类中的start()方法。public void start(){}  (调用此方法,此方法的方法体是run()方法)

范例:启动多线程:

class MyThread extends Thread {// 这就是一个多线程的操作类
	private String name;

	public MyThread(String name) {
		this.name = name;
	}

	@Override
	public void run() {// 覆写run()方法,作为线程的主题操作方法
		for (int x = 0; x < 200; x++) {
			System.out.println(this.name + "-->" + x);
		}
	}
}

public class test {// 主类
	public static void main(String args[]) {
		MyThread mt1 = new MyThread("线程A");
		MyThread mt2 = new MyThread("线程B");
		MyThread mt3 = new MyThread("线程C");

		mt1.start();
		mt2.start();
		mt3.start();
	}
}
  • 为什么多线程启动不是调用run()而必须调用start()?

使用Thread类里面的start()方法,不仅要启动多线程的执行方法,而且还要根据操作系统进行资源的分配;

实现Runnable接口:

Thread类可以实现多线程的主题类定义,但是因为单继承权限,对于类的继承都是应该回避的问题,那么多线程也是一样;为了解决单继承问题出现了Runnable接口,此接口的定义如下:

@FunctionalInterface
public interface Runnable{
	public void run();
}

在接口里任何方法都是public定义的权限,不存在默认的权限;

只需要让一个类实现Runnable接口即可,并且需要覆写run()方法;

如果继承Thread类可以直接使用start()方法,但是如果一个类继承Runnable类,则没有start()方法可以使用;

不管什么情况下,如果想启动多线程,必须依靠Thread类完成;在Thread类定义有以下的构造方法:

构造方法:public Thread(Runnable target),接收的是Runnable接口对象;

范例:启动多线程:

class MyThread implements Runnable {// 这就是一个多线程的操作类
	private String name;

	public MyThread(String name) {
		this.name = name;
	}

	@Override
	public void run() {// 覆写run()方法,作为线程的主题操作方法
		for (int x = 0; x < 200; x++) {
			System.out.println(this.name + "-->" + x);
		}
	}
}

public class test {// 主类
	public static void main(String args[]) {
		MyThread mt1 = new MyThread("线程A");
		MyThread mt2 = new MyThread("线程B");
		MyThread mt3 = new MyThread("线程C");

		new Thread(mt1).start();
		new Thread(mt2).start();
		new Thread(mt3).start();
	}
}

此时避免了单继承局限,在实际工作中使用Runnable接口较好

面试题:多线程两种实现方式的区别?

(或Thread类与Runnable接口实现多线程的区别?)

使用Runnable接口与Thread类相比,解决了单继承的定义局限,如果要使用,一定要使用Runnable接口;

  • Thread类是Runnable接口的子类,使用Runnable接口实现多继承可以解决单继承局限;
  • Runnable接口实现的多线程可以比Thread类更加清楚的描述数据共享的概念;数据共享指的是多个线程访问统一资源的操作;

Callable接口(了解):

因为Runnable接口里面的 run() 方法不返回操作结果(void);为了解决这个问题,出现了Callable接口,定义如下:

@FunctionalInterface //只能有一个方法
public interface Callable<V>{
	public V call() throws Exception;
}

call()方法执行完线程的主题操作后可以返回一个结果,返回结果的类型由泛型决定;

范例:定义一个线程主体类:

class MyThread implements Callable<String> {
	private int ticket = 10;

	@Override
	public String call() throws Exception {
		for (int x = 0; x < 100; x++) {
			if (this.ticket > 0) {
				System.out.println("卖票, ticket = " + this.ticket);
			}
		}
		return "票已卖光!";
	}

}

此时观察Thread类里面发现并没有支持Callable接口的多线程应用;可以通过FutureTask方法接收Callable接口;接收的目的只有一个,取得call()方法的返回结果;

class MyThread implements Callable<String> {
	private int ticket = 10;

	@Override
	public String call() throws Exception {
		for (int x = 0; x < 100; x++) {
			if (this.ticket > 0) {
				System.out.println("卖票, ticket = " + this.ticket--);
			}
		}
		return "票已卖光!";
	}
}

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

		FutureTask<String> task1 = new FutureTask<String>(mt1); // 目的是为了取得call()的返回值
		FutureTask<String> task2 = new FutureTask<String>(mt2);
		
		// FutureTask是Runnable接口子类,所以可以使用Thread类的构造来接收task对象
		new Thread(task1).start();// 启动多线程
		new Thread(task2).start();// 启动多线程
		
		// 多线程执行完成之后可以取得内容,依靠FutureTask的父接口Future中的get()方法完成
		System.out.println("A线程的返回结果:" + task1.get());
		System.out.println("B线程的返回结果:" + task2.get());

	}
}

但是这种方式比较复杂,因为他既要接收返回信息,又要与原始的多线程的实现靠拢(向Thread类靠拢)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值