并发编程基础知识笔记(一)

一、线程

        说到线程大家肯定不陌生,线程是进程中的一个实体,线程本身不会独立存在,进程是代码在数据集合上的一次运行活动,是系统运行资源分配和调度的基本单位,线程是一个执行路径,一个进程至少有一个线程,进程中多个线程共享进程的资源。

        操作系统在分配资源时是把资源分配给进程的,但是cpu资源比较特殊,他是分配到线程的,所以真正占用cpu资源运行的是线程,所以线程也是cpu分配的基本单位。

        在java中我们启动main方法其实是启动了一个JVM的进程,而main函数所在的线程就是这个进程中的主线程。

        说了这么多废话还是不如一张图好理解,废话不多说上图。

                                                                                                   图画的不是很好凑合看吧

        从图上已知的我们看到一个进程中有多个线程,多个线程共享进程和线程的方法区和堆资源,但每个线程由自己独立的程序计数器和栈。问题又来了程序计数器和栈以及堆和方法区又什么东西?

1.1程序计数器(记事本)

        程序计数器其实是一块内存区域,用来记录当前线程记录的线程执行指令的地址。那么为啥程序计数器又是私有的呢?上面说了线程比较特殊是CPU执行的最基本单位,而CPU一般是使用时间片轮转方式让线程轮询占用的,所以当前线程CPU时间片用完后,要让出CPU,等下次轮到自己执行时再执行。那么怎么知道这个线程执行到了哪里?其实程序计数器是记录了该线程让出CPU时执行的地址的,待再次分配到时间片线程就可以从自己私有的计数器指定的地址继续执行。

1.2栈(内心深处的秘密)

        每个线程都有自己的栈资源,用于存储局部变量存储自定义对象的引用地址,这些局部变量,这些局部变量是该线程是私有的,其他线程访问不了的;后面会介绍Threadlocal有异曲同工之妙。除此之外栈还用来存储线程的调用的栈帧(线程调用记录)

1.3堆(真实对象的家,此对象非彼对象)

        堆是一个进程中最大的一块内存,堆是进程中被所有线程共享的,是进程创建时分配的,堆对象里面主要存放new出来的自定义对象的真实实例

1.4方法区(编译后类的家)

        方法区是用来存放JVM加载的类,常量池以及静态变量等信息,他也是线程共享的。这里要说明一下JAVA jdk在不同的版本方法区中放置的东西是不一样的。

1.6:运行时常量池,类的元数据信息,静态变量,编译器编译后的代码等。

1.7:存储的基本和1.6无异,只是把常量池单独拿了出来不再存放在方法区中。

二、JAVA的线程创建与运行

        java中由三种线程创建方式,分别是实现Runnable接口的run方法,集成Thread类并重写run方法,使用FutureTask方式(有返回值)。

2.1实现Runnable接口

public class ThreadTest {

	public static class RunnableTask implements Runnable {
		@Override
		public void run() {
			System.out.println("implements Runnable Thread");
		}
		
	}
	public static void main(String[] args) {
		RunnableTask runnableTask =new RunnableTask();
		new Thread(runnableTask).start();
	}
}

2.2继承Thread类

public static class ThreadTask extends Thread{
		
		@Override
		public void run() {
			System.out.println("extends Thread");
		}
	}
	
	public static void main(String[] args) {
		ThreadTask threadTask =new ThreadTask();
		threadTask.start();
	}

2.3实现Callable接口

//创建一个CallableTask 实现Callable接口中的run方法
public static class CallableTask implements Callable<String>{

		@Override
		public String call() throws Exception {
			return "callable ruturn";
		}
	}
	public static void main(String[] args) {
		//FutureTask构造函数传入一个CallableTask实例
		FutureTask<String> futureTask=new FutureTask<String>(new CallableTask());
		new Thread(futureTask).start();
		try {
			//等待任务执行完成,获取返回值
			String result = futureTask.get();
			System.out.println(result);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

以上描述代码各有优缺点,比如java只支持单继承,实现Runnable以及继承Thread类时都没有返回值等。前两种实现无法拿回任务返回结果而FutureTask却可以。

未完待续。。。

参考书籍:JAVA并发编程之美  -  翟陆续 薛宾田 著

猜你喜欢

转载自blog.csdn.net/m0_37506254/article/details/121323596