Java并发之线程管理(线程基础知识)
线程的创建和运行
1、继承Thread类,并且覆盖run()方法。
2、实现Runnable接口类,使用带参数的Thread构造器来创建Thread对象,参数就是Runnable接口的一个对象。
那么创建完了怎么运行呢?调用run()方法?调用run()方法只是简单的 类对象调用自己的成员方法,那么怎么会开启线程呢?而且每一个线程还有自己的信息(线程名字,线程ID,优先级等)。那么应该是怎么运行呢?答案是调用start()方法。
- 继承Thread类
//创建
public class Thread2 extends Thread{
@Override
public void run() {
System.out.println("继承Thread类创建线程");
}
}
//运行
private static void createThread2() {
Thread2 t2 = new Thread2();
Thread thread = new Thread(t2);
thread.start();
}
- 实现Runnable接口
//创建
public class Thread1 implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable接口创建线程");
}
}
//运行
private static void createThread1() {
Runnable t1 = new Thread1();
Thread thread = new Thread(t1);
thread.start();
}
线程信息的获取和设置
- ID:保存线程的唯一标识符
- Name:线程名称
- Priority:线程对象的优先级,线程优先级从1-10,1是最低优先级,10是最高优先级。
- Status:线程状态。在Java中,线程的状态有6种:new(创建)、runnbale(运行)、blocked(阻塞)、waiting(等待)、time waiting和terminated(终止)。状态转换图:
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
线程的中断
- 调用interrupt()方法,当前执行的线程就会被中断。
task.interrupt();
判断一个线程是否被中断了,有两种方式:
- interrupted(),检查当前执行的线程是否被中断
- isInterrupted():当interrupt()方法被调用时,Thread类中表名线程是否被中断的属性会被设置为true。isInterrupted()方法返回这个属性的值。
推荐使用isInterrupted(),因为interrupted()方法是一个静态方法。
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
线程中断的控制
@Override
public void run() {
File file = new File(initPath);
if (file.isDirectory()) {
try {
dirctoryProcess(file);
} catch (InterruptedException e) {
System.out.printf("%s:the search has been interrupted", Thread.currentThread().getName());
}
}
}
private void dirctoryProcess(File file) throws InterruptedException {
File[] list = file.listFiles();
if (list != null) {
for (int i = 0; i < list.length; i++) {
if (list[i].isDirectory()) {
dirctoryProcess(list[i]);
} else {
fileProcess(list[i]);
}
}
}
if (Thread.interrupted()) {
throw new InterruptedException();
}
}
线程的休眠和恢复
- 休眠指定时间后线程自动恢复
- 线程休眠的方式有两种:
- Thread.sleep(1000);//休眠一秒,其中这里的单位为ms
- TimeUnit.SECONDS.sleep(1);//休眠一秒,这里的单位为s
等待线程的终止(join())
public class DataSourceLoader implements Runnable {
@Override
public void run() {
System.out.printf("Begining data sources loading: %s\n",new Date());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Data Sources loading has finised:%s\n",new Date());
}
}
public class NetWorkConnectionLoader implements Runnable {
@Override
public void run() {
System.out.printf("Begining data sources loading: %s\n",new Date());
try {
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Data Sources loading has finised:%s\n",new Date());
}
}
public class Main {
public static void main(String[] args) {
DataSourceLoader dsLoader = new DataSourceLoader();
Thread t1 = new Thread(dsLoader,"DataSourceThread");
NetWorkConnectionLoader ncLoader = new NetWorkConnectionLoader();
Thread t2 = new Thread(ncLoader,"NetWorkConnectionThread");
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Main: Configuration has been loaded:%s\n",new Date());
}
}
Begining data sources loading: Tue Apr 25 14:46:39 CST 2017
Begining data sources loading: Tue Apr 25 14:46:39 CST 2017
Data Sources loading has finised:Tue Apr 25 14:46:42 CST 2017
NetWorkConnectionLoader loading has finised:Tue Apr 25 14:46:45 CST 2017
Main: Configuration has been loaded:Tue Apr 25 14:46:45 CST 2017
Main: Configuration has been loaded:Tue Apr 25 14:46:45 CST 2017
- join(long milliseconds)
- join(long milliseconds,long nanos)
当一个线程调用其他线程的join()方法时,如果使用的是第一种join()方式,那么它不必等到被调用线程运行终止,如果参数指定的毫秒时钟已经到达,它将继续运行。例如:thread1中有这样的代码thread2.join(1000),thread1将挂起,知道满足下面两个条件之一:
- thread2运行已经完成
- 时钟已经过去了1000毫秒
当两个条件中的任何一个成立是,join()方法将返回。
public final void join() throws InterruptedException {
join(0);
}
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
守护线程的创建和运行
public class WriterTask implements Runnable {
Deque<Event> deque; public WriterTask (Deque<Event> deque){
this.deque=deque;
} @Override
public void run() { // Writes 100 events
for (int i=1; i<100; i++) {
// Creates and initializes the Event objects
Event event=new Event();
event.setDate(new Date());
event.setEvent(String.format("The thread %s has generated an event",Thread.currentThread().getId())); // Add to the data structure
deque.addFirst(event);
try {
// Sleeps during one second
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Event { private Date date;
private String event; public Date getDate() {
return date;
} public void setDate(Date date) {
this.date = date;
} public String getEvent() {
return event;
} public void setEvent(String event) {
this.event = event;
}
}
public class CleanerTask extends Thread {
private Deque<Event> deque; public CleanerTask(Deque<Event> deque) {
this.deque = deque;
// Establish that this is a Daemon Thread
setDaemon(true);
} @Override
public void run() {
while (true) {
Date date = new Date();
clean(date);
}
} private void clean(Date date) {
long difference;
boolean delete; if (deque.size()==0) {
return;
} delete=false;
do {
Event e = deque.getLast();
difference = date.getTime() - e.getDate().getTime();
if (difference > 10000) {
System.out.printf("Cleaner: %s\n",e.getEvent());
deque.removeLast();
delete=true;
}
} while (difference > 10000);
if (delete){
System.out.printf("Cleaner: Size of the queue: %d\n",deque.size());
}
}
}
public static void main(String[] args) { Deque<Event> deque=new ArrayDeque<Event>(); WriterTask writer=new WriterTask(deque);
for (int i=0; i<3; i++){
Thread thread=new Thread(writer);
thread.start();
} CleanerTask cleaner=new CleanerTask(deque);
cleaner.start();
}
线程中不可控异常的处理
- 受检异常(非运行时异常)(Checked Exception)
- 非受检异常(运行时异常)(UnChecked Exception)
由于线程的run()方法不能接受抛出异常,对于受检异常来说,可以在编写程序时捕获,对于非受检异常来说,因为不知道会不会抛出异常,这样就比较麻烦。好在Java提供了一种在线程对象里捕获和处理运行时异常的一种机制。具体如下:
public class ExceptionHandler implements UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.printf("An exception has been captured\n");
System.out.printf("Thread: %s\n",t.getId());
System.out.printf("Exception: %s: %s\n",e.getClass().getName(),e.getMessage());
System.out.printf("Stack Trace: \n");
e.printStackTrace(System.out);
System.out.printf("Thread status: %s\n",t.getState());
}
}
@Override
public void run() {
// The next instruction always throws and exception
int numero=Integer.parseInt("TTT");
}
public static void main(String[] args) {
Task task=new Task();
Thread thread=new Thread(task);
thread.setUncaughtExceptionHandler(new ExceptionHandler());
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.printf("Thread has finished\n");
}
An exception has been captured
Thread: 10
Exception: java.lang.NumberFormatException: For input string: "TTT"
Stack Trace:
java.lang.NumberFormatException: For input string: "TTT"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at com.packtpub.java7.concurrency.chapter1.recipe8.task.Task.run(Task.java:16)
at java.lang.Thread.run(Thread.java:745)
Thread status: RUNNABLE
Thread has finished
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "TTT"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at com.packtpub.java7.concurrency.chapter1.recipe8.task.Task.run(Task.java:16)
at java.lang.Thread.run(Thread.java:745)
Thread has finished
线程局部变量的使用(ThreadLocal)
- 设置临界区,保证临界区里的数据一次只能有一个线程访问
- 为每个线程维护一个该共享数据的局部变量,这样,每个线程各自使用自己的局部变量。ThreadLocal就是这种思路的实现。
- get():返回此线程局部变量的当前线程副本中的值。
- set():将次线程局部变量的当前线程副本中的值设置为指定值。
- remove():移除此线程局部变量当前线程的值。
- initialValue():返回次线程局部变量的当前线程的“初始值”。线程第一次使用get()方法访问变量时将调用此方法,但如果线程之前调用了set(T)方法,则不会对该线程再调用initialValue()方法。通常,此方法对每个线程最多调用一次,但如果在调用get()后又调用了remove(),则可能再次调用此方法。
使用方式如下:
public class SafeTask implements Runnable { private static ThreadLocal<Date> startDate= new ThreadLocal<Date>() {
protected Date initialValue(){
return new Date();
}
}; @Override
public void run() {
// Writes the start date
System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get());
try {
TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
} catch (InterruptedException e) {
e.printStackTrace();
}
// Writes the start date
System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get());
}
}
线程的分组
ThreadGroup threadGroup = new ThreadGroup("Searcher");
SearchTask searchTask=new SearchTask(result);
for (int i=0; i<5; i++) {
Thread thread=new Thread(threadGroup, searchTask);
thread.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void waitFinish(ThreadGroup threadGroup) {
while (threadGroup.activeCount()>9) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
threadGroup.interrupt();
线程组中不可控异常的处理
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
checkAccess();
uncaughtExceptionHandler = eh;
}
class ThreadGroup implements Thread.UncaughtExceptionHandler {
public class MyThreadGroup extends ThreadGroup {
public MyThreadGroup(String name) {
super(name);
}
@Override
public void uncaughtException(Thread t, Throwable e) {
}
}
使用工厂类创建线程
public interface ThreadFactory {
Thread newThread(Runnable r);
}
public class Thread1 implements Runnable{
@override
public void run(){
}
}
Runnable t1 = new Thread1();
Thread t = new Thread(t1);
t.start();
public class MyThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t=new Thread(r,"thread_name");
return t;
}
}
Task task = new Task();
Thread thread=factory.newThread(task);
- 更容易修改类,或者改变创建对象的方式
- 更容易为有限资源创建对象的数目,可以限制一个类型的对象的个数
- 更容易为创建的对象生成统计数据
Java并发之线程管理(线程基础知识)的更多相关文章
- Java做acm所需要的基础知识之排序问题
Java做acm所需要的基础知识. 以前做acm的题都是用C/C++来写代码的,在学习完Java之后突然感觉Java中的方法比C/C++丰富很多,所以就整理一下平时做题需要用到的Java基础知识. 1 ...
- Java基础之线程——管理线程同步方法(BankOperation2)
控制台程序. 当两个或多个线程共享同一资源时,例如文件或内存块,就需要采取措施,确保其中的一个线程不会修改另一个线程正在使用的资源.当其中的一个线程更新文件中的某个记录,同时另一个线程正在检索这个记录 ...
- 别指望一文读懂Java并发之从一个线程开始
Understanding concurrent programming is on the same order of difficulty as understanding object-orie ...
- java笔记--用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程
用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程 ThreadLocal在我的笔记"关于线程同步"的第5种方式里面有介绍,这里就不多说了. ...
- java并发之如何解决线程安全问题
并发(concurrency)一个并不陌生的词,简单来说,就是cpu在同一时刻执行多个任务. 而Java并发则由多线程实现的. 在jvm的世界里,线程就像不相干的平行空间,串行在虚拟机中.(当然这是比 ...
- java第九节 网络编程的基础知识
/** * * 网络编程的基础知识 * 网络协议与TCP/IP * IP地址和Port(端口号) * 本地回路的IP地址:127.0.0.1 * 端口号的范围为0-65535之间,0-1023之间的端 ...
- 学 Java 网络爬虫,需要哪些基础知识?
说起网络爬虫,大家想起的估计都是 Python ,诚然爬虫已经是 Python 的代名词之一,相比 Java 来说就要逊色不少.有不少人都不知道 Java 可以做网络爬虫,其实 Java 也能做网络爬 ...
- (转)JAVA AJAX教程第二章-JAVASCRIPT基础知识
开篇:JAVASCRIPT是AJAX技术中不可或缺的一部分,所以想学好AJAX以及现在流行的AJAX框架,学好JAVASCRIPT是最重要的.这章我给大家整理了一些JAVASCRIPT的基础知识.常用 ...
- Java基础之线程——管理线程同步代码块(BankOperation4)
控制台程序. 除了同步类对象的方法之外,还可以把程序中的语句或代码块制定为synchronized,这种方式更强大,因为可以指定哪个对象从语句或代码块的同步中获益,而不像同步方法那样仅仅是包含代码的对 ...
- iOS/OS X线程安全的基础知识
处理多并发和可重入性问题,是每个库发展过程中面临的比较困难的挑战之一.在Parse平台上,我们尽最大的努力保证你在使用我的SDKs时所做的操作都是线程安全的,保证不会出现性能问题. 在这篇文章中我们将 ...
随机推荐
- OpenGL ES2.0光照
一.简单光照原理 平行光(正常光) 光照效果= 环境颜色 + 漫反射颜色 + 镜面反射颜色 点光源 光照效果= 环境颜色 + (漫反射颜色 + 镜面反射颜色)× 衰减因子 聚光灯 光照效果= ...
- iOS四种多线程(swift和oc)
在这篇文章中,我将为你整理一下 iOS 开发中几种多线程方案,以及其使用方法和注意事项.当然也会给出几种多线程的案例,在实际使用中感受它们的区别.还有一点需要说明的是,这篇文章将会使用 Swift 和 ...
- 解决网络通信中外网和内网之间的通信问题(NAT转换)
本文原址 http://www.cnblogs.com/lidabo/p/3828846.html 在网络编码中会发现程序在局域网中是可以适用的,但是在外网与内网之间和内网与内网之间就不可行.问题就在 ...
- 详解变量声明加 var 和不加 var 的区别
在全局作用域中声明变量加 var 关键字和不加 var ,js 引擎都会将这个变量声明为全局变量,在实际运行时,两种声明方式的变量的行为也是几乎一致的.但是在全局作用域下是否声明一个变量的 时候加va ...
- 快速排序算法分析--C++版
快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试喜欢考这个. 快速排序是C.R.A.Hoar ...
- 关于QQ空间相册功能的构想与简单实现
QQ空间上传照片对其可以分类,形成不同的相册,这对于用户体验来说是很不错的,如果用户只能上传不加以分类,那么用户体验会很差. 下面是自己关于相册功能实现的一些简单看法: 首先,是创建相册,可以用pan ...
- JS的简单用法
JS的简单用法 参考:http://www.w3school.com.cn/js/js_switch.asp JavaScript 是网络的脚本语言 JavaScript 是可插入 HTML 页面的编 ...
- hadoop2的mapreduce操作hbase数据
1.从hbase中取数据,再把计算结果插入hbase中 package com.yeliang; import java.io.IOException; import org.apache.hadoo ...
- 异常详细信息: Abp.AbpException: No language defined!
程序运行后,出现错误:No language defined! 解决方法: 1.检查是否已创建数据库,若未创建则在程序包管理控制台执行命令:Update-Database 2.检查表AbpLangua ...
- Windows Nodejs 安装教程
Windows Nodejs 安装教程 1: 访问官方地址 https://nodejs.org/en/download/ 2: 解压压缩包文件到指定目录 我直接把压缩包解压到C盘根目录下,并将文件夹 ...