线程的实现方式

什么是线程

        线程就是某些进程内部还需要执行多个子任务,我们就把子任务成为线程,线程是进程划分为的更小的运行单位。

        进程和线程的关系就是:一个进程可以包含一个或多个线程,但是至少有一个主线程。

        与进程不同的是,同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或者在各个线程之间做切换工作的时候,负担要比进程小得多。

进程与线程的区别

        根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位;

        资源开销:每个进程都有独立的代码副本和数据空间,进程之间的切换,资源开销较大;线程可以看做轻量级的进程,每个线程都有自己 独立的运行栈和程序计数器,线程之间切换,资源开销小;

        包含关系:一个进程内包含有多个线程,在执行过程,线程的执行不是线性串行的,而是多条线程并行共同完成;

        内存分配:同一进程内的所有线程共享本进程的内存空间和资源;进程之间的内存空间和资源相互独立;

        影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响;一个线程崩溃,会导致整个进程退出。所以多进程要比多线程健壮;

        执行过程:每个独立的进程有程序运行的入口和程序出口。但是线程不能独立执行,必须依存在应用程序(进程)中,由应用程序提供多个线程执行控制;

线程的创建方式

        线程又分为单线程和多线程,单线程就是进程中只有一个线程;多线程是由一个以上的线程组成的程序,在Java中一定是从主线程开始执行。

方式一:继承Thread类

/ 创建线程方式1:继承Thread类  重写run方法
public class Test02 {
	public static void main(String[] args) throws InterruptedException {
		// 每个线程都是一个Thread对象

		System.out.println("主线程执行开始......................");

		// 创建子线程1(继承Thread类)
		Thread thread1 = new Thread("线程1") {
			@Override
			public void run() {
				for (int i = 0; i <= 26; i++) {
					System.out.println("[线程1]" + i);
				}
			}
		};

		// 创建子线程2
		Thread thread2 = new Thread("线程2") {
			@Override
			public void run() {
				for (char c = 'A'; c < 'z'; c++) {
					System.out.println("[线程2]" + c);
				}
			}
		};

//		thread1.join();// 阻断线程
//		thread2.join();

		// 设置优先级
		thread1.setPriority(1);
		thread2.setPriority(10);

		thread1.start();// 启动线程
		thread2.start();// 启动线程

		System.out.println("主线程执行结束......................");
	}
}

1、创建Thread对象;

2、匿名类实现Thread类中的run方法 ;

3、然后调用start方法启动线程。

方式二:实现Runnable接口

// 创建线程方式2:实现Runnable接口
public class Test03 {
	public static void main(String[] args) {

		// 每个Runnable的实现类,封装了线程执行逻辑
		EmailTask email = new EmailTask();

		// 创建三个线程
		Thread t1 = new Thread(email, "线程1");
		Thread t2 = new Thread(email, "线程2");
		Thread t3 = new Thread(email, "线程3");

		// 启动线程
		t1.start();
		t2.start();
		t3.start();

	}
}

class EmailTask extends Task implements Runnable {

	@Override
	public void execute() {
		// 获取当前线程对象
		Thread t = Thread.currentThread();

		// 获取线程名称
		String name = t.getName();

		System.out.println(name + "发送邮件成功");
	}

	@Override
	public void run() {
		execute();
	}

}

abstract class Task {

	public abstract void execute();
}

方式三:实现Callable接口,允许子线程返回结果,抛出异常

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

// 线程创建方法3:实现Callable接口
public class Test04 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {

		// Callable接口实现类:不同数据范围的计算任务
		SumCalcTask sumTask1 = new SumCalcTask(1, 300);
		SumCalcTask sumTask2 = new SumCalcTask(301, 500);
		SumCalcTask sumTask3 = new SumCalcTask(501, 1000);
		SumCalcTask sumTask = null;

		// Callable------> FutureTask(Runnable接口实现类)
		FutureTask<Integer> ftask1 = new FutureTask<Integer>(sumTask1);
		FutureTask<Integer> ftask2 = new FutureTask<Integer>(sumTask2);
		FutureTask<Integer> ftask3 = new FutureTask<Integer>(sumTask3);

		// 创建并启动线程
		Thread th1 = new Thread(ftask1);
		Thread th2 = new Thread(ftask2);
		Thread th3 = new Thread(ftask3);

		// ftask1.run() ----> Callable.call() --->结果 --->outcome
		th1.start();
		th2.start();
		th3.start();

		// 线程执行结束,分别获取线程执行返回的结果
		Integer sum1 = ftask1.get();
		Integer sum2 = ftask2.get();
		Integer sum3 = ftask3.get();

		Integer res = sum1 + sum2 + sum3;

		System.out.println(res);

	}
}

// 通过Callable实现类SumCalcTask封装某个范围数据的累加和
class SumCalcTask implements Callable<Integer> {

	private int begin, end;

	public SumCalcTask(int begin, int end) {
		this.begin = begin;
		this.end = end;
	}

	@Override
	public Integer call() throws Exception {

		int res = 0;
		for (int i = begin; i <= end; i++) {
			res += i;
		}
		return res;
	}
}

1、实现Callable接口需要创建一个FutureTask来接受Callable;

2、FutureTask是Runnable的实现类;

3、 最后同样创建Thread对象启动线程。

方式四:线程池

        线程池,按照配置参数(核心线程数、最大线程数等)创建并管理若干线程对象。程序中如果需要使用线程,将一个执行任务传给 线程池,线程池就会使用一个空闲状态的线程来执行这个任务。执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状 态,等待执行下一个任务。使用线程池可以很好地提高性能。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// 创建线程方法4:通过线程池创建
public class Test05 {
	public static void main(String[] args) {

		// 创建固定数量的线程池
		ExecutorService executorService = Executors.newFixedThreadPool(10);

		// 不确定数量的线程请求
		while (true) {
			// 向线程池提交一个执行任务(Runnable接口实现类对象)
			// 线程池分配一个“空闲线程”执行任务
			// 如果没有空闲线程,则该任务加入等待队列 (工作队列)
			executorService.execute(new Runnable() {

				@Override
				public void run() {
					System.out.println(Thread.currentThread().getName() + "进行了1次投票");
					try {
						Thread.sleep(1000);// 当前线程休眠1000毫秒
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
	}
}

1、使用Executors.newFixedThreadPool(10)创建一个固定大小的线程池;

2、调用execute方法启动线程。

扩展:线程池执行Callable接口封装的线程任务

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

// 线程池执行Callable接口封装的线程任务
public class Test06 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {

		// Callable接口实现类:不同数据范围的计算任务
		SumCalcTask sumTask1 = new SumCalcTask(1, 300);
		SumCalcTask sumTask2 = new SumCalcTask(301, 500);
		SumCalcTask sumTask3 = new SumCalcTask(501, 1000);

		// 线程池
		ExecutorService executorService = Executors.newFixedThreadPool(3);

		// 提交线程任务
		Future<Integer> f1 = executorService.submit(sumTask1);
		Future<Integer> f2 = executorService.submit(sumTask2);
		Future<Integer> f3 = executorService.submit(sumTask3);

		int res1 = f1.get();
		int res2 = f2.get();
		int res3 = f3.get();

		System.out.println(res1 + res2 + res3);

		// 关闭线程池
		executorService.shutdownNow();
	}
}

1、同样使用一个Future对象来接受线程任务;

2、最后关闭线程池。

归根结底,其实创建线程的方法只有一种:创建Thread对象!!!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农叮叮车

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值