线程的基本介绍 一

1.并发简史: 线程和进程之间的关系以及为什么要使用线程。

        在早期的计算器系统中不存在操作系统,他从头到尾只能执行一个程序,这个程序能够访问计算机中的所有资源,在这种环境中,不仅程序很难编写,而且极大的造成资源的浪费。操作系统的出现使得可以运行多个程序在上面,这些程序运行在不同的进程中上,操作系统来管理分配给这些进程运行的资源,内存、文件句柄、安全证书等。不同的进程之间可以通过一些手段来通信,包括套接字、共享内存以及文件等。之所以引入操作系统就是为了更合理的使用系统的资源,提高资源的利用率;为了满足公平性,不同的用户和不同的程序都可以同时的访问计算机上的资源,通过时间片的机制类来共享资源,而不仅仅是一个程序从头运行到尾;便利性,通常来说在计算多个任务时,都是编写多个程序,程序之间通过通信机制来相互联系这比仅仅编写一个程序要容易的多。

这些因素同时促进了线程的发展,线程允许在一个进程中存在多个的程序控制流,多个线程共享进程中的资源包括 内存句柄,文件句柄;每一个线程又存在着自己的程序计数器,栈以及局部变量。线程也被称为轻量级的进程,在大多数的操作系统中都是以线程为程序调度的基本单位而不是进程。由于同一个进程上的线程都共享着这个进程上的内存地址和空间,因此这些线程都可以访问同一个变量并在同一个堆上分配对象。如果没有明确的协同机制,当一个线程在访问进程上的一个变量时,另一个线程可能同时访问这个变量,这就可能造成无法估量的后果。

 

2.线程的创建方式:

① 可以通过继承Thread类:

package com.wc.study.thread.demo1;

public class CreateThreadByExtends extends Thread{
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		Thread thread1 = new CreateThreadByExtends();
		Thread thread2 = new CreateThreadByExtends();
		thread1.start();
		thread2.start();
	}
}

② 实现Runnable接口:

package com.wc.study.thread.demo1;

public class CreateThreadByRunnable implements Runnable{
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
	
	public static void main(String[] args) {
		Thread thread1 = new Thread(new CreateThreadByRunnable());
		Thread thread2 = new Thread(new CreateThreadByRunnable());
		thread1.start();
		thread2.start();
	}
}

③通过Callable接口来创建线程:

public class CreateThreadByCallable implements Callable<String>{

	@Override
	public String call() throws Exception {
		return Thread.currentThread().getName();
	}
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<String> futureTask1 = new FutureTask<>(new CreateThreadByCallable());
		FutureTask<String> futureTask2 = new FutureTask<>(new CreateThreadByCallable());
		Thread thread1 = new Thread(futureTask1);
		Thread thread2 = new Thread(futureTask2);
		thread1.start();
		thread2.start();
		System.out.println(futureTask1.get());
		System.out.println(futureTask2.get());
	}
}

④通过线程池来创建线程:

 1) 通过Executors创建无返回值的线程:

package com.wc.study.thread.demo1;

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

public class CreateThreadByExecutor {
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
		executorService.execute(()-> System.out.println(Thread.currentThread().getName()));
		
		executorService.shutdown();
	}
}

2) 通过Executors创建有返回值的线程:

package com.wc.study.thread.demo1;

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

public class CreateThreadByExecutors2 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService executorService = Executors.newFixedThreadPool(5);
		Future<String> future1 = executorService.submit(() -> {
			return Thread.currentThread().getName();
		});
		Future<String> future2 = executorService.submit(() -> {
			return Thread.currentThread().getName();
		});
		System.out.println(future1.get());
		System.out.println(future2.get());
		
		executorService.shutdown();
	}
}

总结: 

创建线程分为两种: 有返回值和没有返回值。 没有返回值推荐使用实现Runnable的方法 重写其中的 run(),创建有返回值的线程实现Callable接口,重写其中的call() 方法,返回值为FutureTask,此类实现了RunnableFuture接口,是Runnable接口的子类,可以通过get() 方法获取到想要的返回值.

在使用线程池创建线程时,使用submit来提交创建的线程,创建有返回值的线程返回Future,可以通过get() 方法获取到返回值,创建没有返回值的线程可以通过 executor() 方法和submit(),而创建有返回值的只有通过submit()方法.

猜你喜欢

转载自blog.csdn.net/csdn_wangchen/article/details/84615145
今日推荐