高并发编程_Java线程基础 1.线程简介

高并发编程_Java线程基础 1.线程介绍

1.进程、线程之间的区别

我们都知道,现在的系统都是多进程、多用户的,像Linux、Unix、windows。不仅同时可以登录多个用户进行操作,而且允许同时运行多个进程(当然,window是伪多用户的,因为对于Windows来说,一个用户登录,只能注销当前登录用户,切换到另一个用户。但是对于Linux、Unix来说,是真正的多用户操作,可同时登录多个用户进行同时操作)。

进程:进程是系统分配资源以及调度运行的基本单位。当前系统中每一个运行中的程序就是一个进程。与线程之间最大的区别就是进程之间相互独立,不可进行资源共享。当然这个也不是绝对的,可以通过共享内存的方式实现资源共享。

线程:线程存在于进程中,一个进程中可以存在一个至多个线程,但一个线程只能属于一个进程,是系统最小的执行单元。程序中每一块运行中的代码块都是一个线程。对于系统分配给进程的资源,该进程中的所有的线程共享该资源。但资源共享,同时也会带来共享资源的安全问题。

2.Java中线程相关的类以及线程的创建

创建线程有两种方式,分别是集成Thread类以及实现Runable接口。

2.1集成Thread类,创建线程

public class ThreadCreate extends Thread{

	@Override
	public void run() {
		System.out.println("执行业务逻辑");
	}
	
	public static void main(String[] args) {
		ThreadCreate thread = new ThreadCreate();
		thread.setName("test");
		thread.start();
		System.out.println("the current thread name is " + thread.getName());
	}
}

2.2实现Runable接口,创建线程

public class ThreadCreate2 implements Runnable{

	@Override
	public void run() {
		System.out.println("执行业务逻辑");
	}
	
	public static void main(String[] args) {
		ThreadCreate2 t = new ThreadCreate2();
		Thread thread = new Thread(t);
		thread.setName("test2");
		thread.start();
		System.out.println("the current thread name is " + thread.getName());
	}

}

对于Java中的线程来说,真正表示线程的类只有Thread类。而Runable的接口是通过run()方式实现业务逻辑与线程的分离功能。

3.线程类Thread构造方法以及start方法、setName方法源码解析

Thread类位于java.lang包下面,Java 8 API:https://docs.oracle.com/javase/8/docs/api/

Thread本身同样实现了Runable接口,重写了run方法,是与实现与线程无关的业务逻辑处理。

3.1Thread 构造方法

Thread类的构造方法有8个,下面一一借助源码进行解析

1.new Thread(),无任何参数。源码如下:

/**
*无参构造器,调用Thread init方法,init方法分别需要5个参数。
*5个参数作用分别于下面解释
*/
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
}

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
	if (name == null) {
		throw new NullPointerException("name cannot be null");
	}

	this.name = name;

	Thread parent = currentThread();
	SecurityManager security = System.getSecurityManager();
	if (g == null) {
		/* Determine if it's an applet or not */

		/* If there is a security manager, ask the security manager
		   what to do. */
		if (security != null) {
			g = security.getThreadGroup();
		}

		/* If the security doesn't have a strong opinion of the matter
		   use the parent thread group. */
		if (g == null) {
			g = parent.getThreadGroup();
		}
	}

	/* checkAccess regardless of whether or not threadgroup is
	   explicitly passed in. */
	g.checkAccess();

	/*
	 * Do we have the required permissions?
	 */
	if (security != null) {
		if (isCCLOverridden(getClass())) {
			security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
		}
	}

	g.addUnstarted();

	this.group = g;
	this.daemon = parent.isDaemon();
	this.priority = parent.getPriority();
	if (security == null || isCCLOverridden(parent.getClass()))
		this.contextClassLoader = parent.getContextClassLoader();
	else
		this.contextClassLoader = parent.contextClassLoader;
	this.inheritedAccessControlContext =
			acc != null ? acc : AccessController.getContext();
	this.target = target;
	setPriority(priority);
	if (inheritThreadLocals && parent.inheritableThreadLocals != null)
		this.inheritableThreadLocals =
			ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
	/* Stash the specified stack size in case the VM cares */
	this.stackSize = stackSize;

	/* Set thread ID */
	tid = nextThreadID();
}

2.new Thread(Runable target),参数为Runable类型。

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

该构造方法,内部同样调用init方法,传入的参数target具体如何使用,在源码里面并没有找到。个人想法应该是JVM底层在调用本地方法时做了相应的处理。

3.new Thread(Runable target,String name),参数为Runable类型以及一个String类型的线程名字。

public Thread(ThreadGroup group, String name) {
    init(group, null, name, 0);
}

该构造方法,内部同样调用init方法,同时传入target以及线程的名称。通过该构造方法,在初始化Thread的时候,指定线程的名称。

4.new Thread(String name),传入线程名称

该构造方法,内部同样调用init方法,初始化时指定线程的名称。

5.new Thread(ThreadGroup group, Runnable target),传入target以及线程所属组

该构造方法,内部同样调用init方法、如果传入的ThreadGroup为null,值为当前线程的ThreadGroup赋值为调用线程的ThreadGroup。


private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
	if (name == null) {
		throw new NullPointerException("name cannot be null");
	}

	this.name = name;

	Thread parent = currentThread();
	SecurityManager security = System.getSecurityManager();
	if (g == null) {
		/* Determine if it's an applet or not */

		/* If there is a security manager, ask the security manager
		   what to do. */
		if (security != null) {
			g = security.getThreadGroup();
		}

		/* If the security doesn't have a strong opinion of the matter
		   use the parent thread group. */
		if (g == null) {
			g = parent.getThreadGroup();
		}
	}

	/* checkAccess regardless of whether or not threadgroup is
	   explicitly passed in. */
	g.checkAccess();

	/*
	 * Do we have the required permissions?
	 */
	if (security != null) {
		if (isCCLOverridden(getClass())) {
			security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
		}
	}

	g.addUnstarted();

	this.group = g;
	this.daemon = parent.isDaemon();
	this.priority = parent.getPriority();
	if (security == null || isCCLOverridden(parent.getClass()))
		this.contextClassLoader = parent.getContextClassLoader();
	else
		this.contextClassLoader = parent.contextClassLoader;
	this.inheritedAccessControlContext =
			acc != null ? acc : AccessController.getContext();
	this.target = target;
	setPriority(priority);
	if (inheritThreadLocals && parent.inheritableThreadLocals != null)
		this.inheritableThreadLocals =
			ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
	/* Stash the specified stack size in case the VM cares */
	this.stackSize = stackSize;

	/* Set thread ID */
	tid = nextThreadID();
}

6.new Thread(ThreadGroup group, Runnable target, String name),传入线程所属线程组,以及各target,线程名字

该构造方式同5相同,不同的是该构造方法在初始化的时候会为线程指定名称。

7.new Thread(ThreadGroup group, String name),传入线程所属线程组以及线程名称

该构造方法同6

8.new Thread(ThreadGroup group, Runnable target, String name, long stackSize),stackSize为线程分配线程在栈中的所拥有栈内存大小,该方法高度依赖平台,也就是说在某些平台上不一定起作用。该方法一般不常用。

每个线程在创建是,都会在JVM的栈内存中开辟一块空间,该快栈内存的空间大小,决定了该线程所占用的内存的大小,当线程占用的内存大小超过,将会抛出SecurityException 异常,如Java官网所说(if the current thread cannot create a thread in the specified thread group)。

3.2 Thread start方法

Thread类的start方法用于启动一个,在调用start方法时,首先会调用Java本地方法,start0(),而Java本地方法start0()不仅会启动一个线程,同时会去调用run()方法,执行业务逻辑。所以,这也是为什么不能直接通过调用run方法来启动一个线程的原因。因为如果直接调用run方法,他并没有启动一个线程,只是相当于通过Thread实例类,调用一个普通的方法,而这个普通的方法就是run而已。

start方法源码如下:

 public synchronized void start() {
	/**
	 * This method is not invoked for the main method thread or "system"
	 * group threads created/set up by the VM. Any new functionality added
	 * to this method in the future may have to also be added to the VM.
	 *
	 * A zero status value corresponds to state "NEW".
	 */
	if (threadStatus != 0)
		throw new IllegalThreadStateException();

	/* Notify the group that this thread is about to be started
	 * so that it can be added to the group's list of threads
	 * and the group's unstarted count can be decremented. */
	group.add(this);

	boolean started = false;
	try {
		start0();
		started = true;
	} finally {
		try {
			if (!started) {
				group.threadStartFailed(this);
			}
		} catch (Throwable ignore) {
			/* do nothing. If start0 threw a Throwable then
			  it will be passed up the call stack */
		}
	}
}

private native void start0();

/**
 * If this thread was constructed using a separate
 * <code>Runnable</code> run object, then that
 * <code>Runnable</code> object's <code>run</code> method is called;
 * otherwise, this method does nothing and returns.
 * <p>
 * Subclasses of <code>Thread</code> should override this method.
 *
 * @see     #start()
 * @see     #stop()
 * @see     #Thread(ThreadGroup, Runnable, String)
 */
@Override
public void run() {
	if (target != null) {
		target.run();
	}
}

3.3 Thread setName方法

setName方法源码如下:

public final synchronized void setName(String name) {
	checkAccess();
	if (name == null) {
		throw new NullPointerException("name cannot be null");
	}

	this.name = name;
	if (threadStatus != 0) {
		setNativeName(name);
	}
}

 

此次线程相关介绍就到这里,如有描述不当地方,请指正。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值