一起学并发编程
来源:互联网 发布:淘宝网中年雪纺衫 编辑:程序博客网 时间:2024/05/01 19:06
今天研究了下
Java
线程基础知识,发现以前太多知识知识略略带过了,比较说Java的线程机制,在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程),以及构造器中的stackSize
…..
守护线程
估计学过Unix
开发但是没有细致学习Java
的同学们会疑惑了,操作系统里面是没有所谓的守护线程的概念,只有守护进程一说,但是Java
语言机制是构建在JVM的基础之上的,意思是Java
平台把操作系统的底层给屏蔽起来,所以它可以在它自己的虚拟的平台里面构造出对自己有利的机制,而语言或者说平台的设计者多多少少是受到Unix
思想的影响,而守护线程机制又是对JVM
这样的平台凑合,于是守护线程应运而生。
Daemon
的作用是为其他线程的运行提供服务,比如说GC
线程。其实User Thread
线程和Daemon Thread
守护线程本质上来说去没啥区别的,唯一的区别之处就在虚拟机的离开:如果User Thread
全部撤离,那么Daemon Thread
也就没啥线程好服务的了,所以虚拟机也就退出了。
守护线程并非虚拟机内部可以提供,用户也可以自行的设定守护线程,方法:setDaemon(boolean on)
但是有几点需要注意:
thread.setDaemon(true)
必须在thread.start()
之前设置,否则会跑出一个IllegalThreadStateException
异常,因为你不能把正在运行的常规线程
设置为守护线程
。(备注:这点与守护进程有着明显的区别,守护进程是创建后,让进程摆脱原会话的控制+让进程摆脱原进程组的控制+让进程摆脱原控制终端的控制;所以说寄托于虚拟机的语言机制跟系统级语言有着本质上面的区别)
public final void setDaemon(boolean on) { checkAccess(); if (isAlive()) {//如果处于运行状态,抛出异常 throw new IllegalThreadStateException(); } daemon = on;}
在
Daemon
线程中产生的新线程也是Daemon
的。(这一点又是有着本质的区别了:守护进程fork()
出来的子进程不再是守护进程
,尽管它把父进程的进程相关信息复制过去了,但是子进程的进程的父进程不是init
进程,所谓的守护进程
本质上说就是父进程挂掉,init收养
)不是所有的应用都可以分配给
Daemon
线程来进行服务,比如读写操作
或者计算逻辑
。因为在Daemon Thread
还没来的及进行操作时,虚拟机可能已经退出了。
Thread thread = new Thread(() -> { Thread innerThread = new Thread(() -> { try { for (int i = 1; i < 10; i++) { Thread.sleep(1_000); System.out.println("守护线程 " + i); } } catch (InterruptedException e) { e.printStackTrace(); } }); innerThread.setDaemon(true); innerThread.start(); try { for (int i = 1; i < 6; i++) { Thread.sleep(1_000); System.out.println("常规线程 " + i); } } catch (InterruptedException e) { e.printStackTrace(); }});thread.start();
日志分析
常规线程 1守护线程 1守护线程 2常规线程 2守护线程 3常规线程 3守护线程 4常规线程 4守护线程 5常规线程 5
从上面的日志中可以看到,如果将innerThread
设置成守护模式
,那么待当前主线程完成处理退出后,守护线程
也会随着销毁
JRE判断程序是否执行结束的标准是所有的前台执线程行完毕了,而不管后台线程的状态,因此,在使用后台线程候一定要注意这个问题。
那么daemon Thread
实际应用在那里呢?举个例子,Web
服务器中的Servlet
,容器启动时后台初始化一个服务线程,即调度线程
,负责处理http
请求,然后每个请求过来调度线程
从线程池
中取出一个工作者线
程来处理该请求,从而实现并发控制的目的。
线程函数
在学习Thread
的时候,常见写法就是Runnable
和ThreadName
,所以这里重点讲解ThreadGroup
以及stackSize
的作用
public Thread(); public Thread(Runnable target); public Thread(String name); public Thread(Runnable target, String name); public Thread(ThreadGroup group, Runnable target); public Thread(ThreadGroup group, String name); public Thread(ThreadGroup group, Runnable target, String name); public Thread(ThreadGroup group, Runnable target, String name, long stackSize);
- 第一种是实例化一个无参构造函数,
ThreadName
与GroupName
为系统默认 - 第二种是实现了
Runnable
接口的类的实例,Thread
类也实现了Runnable
接口,因此,从Thread
类继承的类的实例也可以作为target
传入这个构造方法。 - 第三种是可以自定义
ThreadName
- 第五种是可以指定该线程属于哪个
ThreadGroup
(线程组) - 第八种是可以指定
堆栈大小
(比如压栈大小),这个值一般是CPU页面的整数倍,如x86的页面大小是4KB.在x86平台下,默认的线程栈大小是12KB.
ThreadName
,可以通过创建Thread
实例后调用,setName
方法设置。默认线程名:Thread-N,N是线程建立的顺序,是一个不重复的正整数,它的来源基于Thread.nextThreadNum()
/* For autonumbering anonymous threads. */private static int threadInitNumber;private static synchronized int nextThreadNum() { return threadInitNumber++;}
stackSize
是一种具有平台依赖性的参数,它能指定堆栈的大小。 在某些平台上,指定一个较高的stackSize
参数值可能使线程在抛出StackOverflowError
之前达到较大的递归
深度。stackSize
参数的值与最大递归深度和并发程度之间的关系细节与平台有关。在某些平台上,stackSize
参数的值无论如何不会起任何作用。作为建议,可以让虚拟机自由处理stackSize
参数。
ThreadGroup group = new ThreadGroup("battcn-group");Thread t1 = new Thread(() -> System.out.println("hello my name's" + Thread.currentThread().getName() + " group name's" + Thread.currentThread().getThreadGroup().getName()));Thread t2 = new Thread(() -> System.out.println("hello my name's" + Thread.currentThread().getName() + " group name's" + Thread.currentThread().getThreadGroup().getName()), "thread-battcn2");Thread t3 = new Thread(() -> System.out.println("hello my name's" + Thread.currentThread().getName() + " group name's" + Thread.currentThread().getThreadGroup().getName()), "thread-battcn3");t1.start();t2.start();t3.start();group.enumerate(new Thread[]{t2, t3});
以下是上部代码片段的日志输出,可以看到指定ThreadName
与ThreadGroup
以及不指定的的区别
hello my name's Thread-0 group name'smainhello my name's thread-battcn2 group name'smainhello my name's thread-battcn3 group name'smain
警告 如果对
stackSize
有兴趣的可以试试下面代码,不过慎重,有可能吧你电脑内存跑完….
for (int i = 0; i < Integer.MAX_VALUE; i++) { new Thread(group, new Runnable() { @Override public void run() { try { add(1); } catch (Error error) { System.out.println(count); error.printStackTrace(); } } private void add(int i) { count++; add(i + 1); } }, "thread-battcn-4",1 << 24).start();}
- 说点什么
全文代码:https://git.oschina.net/battcn/battcn-concurent
- 个人QQ:1837307557
- battcn开源群(适合新手):391619659
微信公众号:battcn
(欢迎调戏)
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学并发编程
- 一起学编程(1)
- 看动画学并发编程
- 看动画学并发编程
- 面向方面编程,有兴趣的一起学
- 《与孩子一起学编程》译者序
- 《与孩子一起学编程》书评
- 与孩子一起学编程1
- ListView实现item单选、多选效果(没使用复选框) checkable接口
- Spring Cloud构建微服务架构服务容错保护
- linux下mysql安装
- Linux网络基础
- eclipse 中的注释 快捷键
- 一起学并发编程
- xadmin的csv导出中文乱码的问题
- Announcing TensorFlow Lite
- 一张图总结Google C++编程规范(Google C++ Style Guide)
- 欧几里德算法 -- 求最大公约数
- Runtime Permissions(郭霖CSDN公开课)
- HLS-序
- lua pcall error
- SVN服务器搭建和使用(一)