线程的创建和运行
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时所做的操作都是线程安全的,保证不会出现性能问题. 在这篇文章中我们将 ...
随机推荐
-
33个超级有用必须要收藏的PHP代码样例
作为一个正常的程序员,会好几种语言是十分正常的,相信大部分程序员也都会编写几句PHP程序,如果是WEB程序员,PHP一定是必备的,即使你没用开发过大型软件项目,也一定多少了解它的语法. 在PHP的流行 ...
-
(十二) WebGIS中矢量图层的设计
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.前言 在前几章中我们已经了解了什么是矢量查询.屏幕坐标与地理坐标之 ...
-
烂泥:智能DNS使用与配置
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 公司的业务现在已经扩展到海外,对外提供的统一接口都是通过域名来解析的,但是海外用户访问国 ...
-
C 语言学习 第二次作业总结
本次作业内容,主要有以下几点: 新建 coding 帐号,且使用 coding 上传本次作业的代码 Printf及条件判断语句的使用 作业总结 作业总结: 同学们开始渐入佳境,能够较为流畅的写出合理的 ...
-
mac mysql cmd
sudo /usr/local/mysql/support-files/mysql.server start sudo /usr/local/mysql/support-files/mysql.ser ...
-
cuda编程基础
转自: http://blog.csdn.net/augusdi/article/details/12529247 CUDA编程模型 CUDA编程模型将CPU作为主机,GPU作为协处理器(co-pro ...
-
安装微软ASP.NET MVC 4,运行以下的包管理器控制台命令
(菜鸟,勿喷,有错求指正)Asp.net 新建的类库中安装MVC4 .下面是步骤,1+2:打开程序包管理控制台,3:运行Install-Package Microsoft.AspNet.Mvc - ...
-
State of Hyperparameter Selection
State of Hyperparameter Selection DANIEL SALTIEL VIEW NOTEBOOK Historically hyperparameter determina ...
-
Linux [Ubuntu 12.0.1] 常用命令
1.文件名颜色的含义1)默认色代表普通文件.例:install.log2)绿色代表可执行文件.例:rc.news3)红色代表tar包 文件. 例:vim-7.1.tar.bz24)蓝色代表目录文件. ...
-
读书笔记:《重来REWORK》
读书笔记:<重来REWORK> <重来Rework--更为简单有效的商业思维>这本书是看了别人的书单而购买的,初 拿到这本书翻看时,感觉有两点与平常的书不同,一是每个小节非常短 ...