本文主要是以知识点的形式对java多线程进行了解,学习java多线程的基础,本文参考书籍《java并发编程实战手册》,若有兴趣想研究跟高级的多线程思想,可以阅读《java并发编程实战》。
1.线程的创建和运行
java线程的创建有三种方式,可能大部分人只知道常用的两种:
1.继承Thread类,并且覆盖run()方法。
2.创建一个实现Runnable接口的类。使用带参数的Thread构造器来创建Thread对象。
3.使用Callable与Future来创建启动线程
1.创建Callable的实现类,并重写call()方法,该方法为线程执行体,并且该方法有返回值
2.创建Callable的实例,并用FutuerTask类来包装Callable对象,该FutuerTask封装了Callable对象call()方法的返 回值
3.实例化FutuerTask类,参数为FutuerTask接口实现类的对象来启动线程
4.通过FutuerTask类的对象的get()方法来获取线程结束后的返回值
下面给出第三种的示例代码:
<span style="font-family:Comic Sans MS;">import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class ThirdThread implements Callable<Integer>{
public Integer call(){
int i = 0;
for( ; i<60; i ++){
System.out.println(Thread.currentThread().getName() + "循环变量i的值是 : " + i);
}
return i;
}
public static void main(String[] args) {
ThirdThread rt = new ThirdThread(); //创建Callable对象
FutureTask<Integer> task = new FutureTask<Integer>(rt);//使用FutrueTask来包装Callable对象
for(int i=0 ; i<60 ; i++){
System.out.println(Thread.currentThread().getName() + "-------" + i);
if(i == 10){
new Thread(task, "有返回值的线程").start(); //实际上还是以Callable对象创建并启动线程
}
}
try{
System.out.println("子线程的返回值 :" + task.get());
}
catch(Exception e){
e.printStackTrace();
}
}
}</span>
2. 线程信息
Thread类有一些保存信息的属性,这些属性可以用来标示线程,显示线程的状态或者控制线程的优先级。
ID :保存了线程的唯一标识符
Name:保存了线程的名称
Priority:保存了线程对象的优先级。线程的优先级是1-10,其中1的优先级最低。
Status:保存了线程的状态。在java中线程的状态有6中 new 、runnable、blocked 、waiting、time waiting或者terminated。
3.线程的中断
如果一个java程序有不止一个执行线程,当所有线程都运行结束的时候这个java程序才能运行结束,更确切的说所有的非守护线程运行结束时或者其中一个线程调用了system.exit()方法时,这个java程序才运行结束。java线程中断
thread.interrupt()方法,中断线程,这只是一个标识,执行了此方法thread依然能继续运行,若想在线程中回应这个中断可以设置,判断是否中断,并且 return方法体,退出执行,倘若要中断多个方法或者在递归中中断,一个return是不够的,因此需要throw InterruptedException 来中断执行。
注意:检查线程是否中断可以使用 Thread的静态方法interrupted()此方法可以改变interrupted的状态,推荐使用第二种,isInterrupted()方法。
4.线程的休眠与等待线程终止
第一种调用线程的sleep方法,第二种通过TimeUnit枚举类元素进行调用。如果在休眠过程中的线程被中断就立即抛出 throw InterruptedException异常。
join方法可以等待线程结束或者一定时间在执行下面的程序。
5.守护线程的创建
守护线程就是一种后台服务线程,一旦有用户线程在运行,守护线程就要一直在运行,可以通过将setDaemon设置为守护线程。
6.线程的局部变量使用
使用一个Runnable实现类可以创建多个线程,但是这个类中的变量是共享的,为了避免这种情况引入ThreadLocal。
示例:
private static ThreadLOcal<Date> startDate = new ThreadLocal<Date>(){
protected Date initialValue(){
return new Date();
}
};
ThreadLocal为每个线程存储了各自的属性值。
7.线程的分组与使用工厂创建线程
创建线程时可以讲线程加入ThreadGroup中。
使用工厂创建线程,实现ThreadFactory接口并且重写newThread方法。