在计算机领域中,我们说的并发(Concurrency)是指一系列任务的同时运行。如果一台电脑有多个处理器或者有一个多核处理器,这个同时性(Simultaneity)是真正意义的并发;但是如果一台电脑只有一个单核处理器,这个同时性并不是真正的并发
一、线程的创建和运行
继承Thread类,并覆盖run()方法
创建一个Runnable接口的类。使用带参数的Thread构造器来创建Thread对象。这个参数就是实现Runnable接口的类的一个对象
范例实现:
package org.test.concurrency;
/**
* @author kucs
*
* 创建一个实现Runnable接口的类。使用带参数的Thread构造器来创建对象
* 这个参数就是实现Runnable接口的类的一个对象
*
*/
public class Calculator implements Runnable {
private int number;
public Calculator(int number) {
this.number = number;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i < 10;i++){
System.out.printf("%s: %d * %d = %d\n", Thread.currentThread().getName(),number,i,i*number);
}
}
}
package org.test.concurrency;
public class Main {
public static void main(String[] args) {
/* 创建一个执行10次的循环
* 每次循环创建一个Calculator对象和一个Thread对象
* 这个Thread对象使用刚创建的Calculator对象作为构造器的参数
* 然后调用刚创建的Thread对象的start()方法
*/
for(int i = 0;i < 10;i++){
Calculator calculator = new Calculator(i);
Thread thread = new Thread(calculator);
thread.start();
}
}
}
运行结果
当调用Thread对象的start()方法时,另一个执行线程将被创建。
如果某一个线程调用了System.exit()指令来结束程序的执行,所有的线程都将结束
对于一个实现了Runable接口的类来说,创建Thread对象并不会创建一个新的执行线程;同样的,调用它的run()方法,也不会创建一个新的线程。只有调用它的start()方法,才会创建一个新的执行线程。
二、线程信息的获取和设置
Thread类有一些保存信息的属性。这些属性可以用来标识线程的状态或者控制线程的优先级。
ID:保存了线程唯一的标识符
Name:保存了线程名
Priority:保存了线程对象的优先级。线程的优先级从1到10逐次递增。不建议改变线程优先级
Status:保存了线程的状态。在java中,线程有6中状态:new,runnable,blocked,waiting,time waiting或者terminated
jdk6版本的的Thread部分源码
public class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
private char name[];
private int priority;
private Thread threadQ;
private long eetop;
/* Whether or not to single_step this thread. */
private boolean single_step;
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false;
/* JVM state */
private boolean stillborn = false;
/* What will be run. */
private Runnable target;
/* The group of this thread */
private ThreadGroup group;
/* The context ClassLoader for this thread */
private ClassLoader contextClassLoader;
/* The inherited AccessControlContext of this thread */
private AccessControlContext inheritedAccessControlContext;
/* For autonumbering anonymous threads. */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
private long stackSize;
/*
* JVM-private state that persists after native thread termination.
*/
private long nativeParkEventPointer;
/*
* Thread ID
*/
private long tid;
我们对Main类进行改造,代码如下
package org.test.concurrency;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.State;
public class Main {
public static void main(String[] args) {
/*
* 创建一个容量为10的线程数组,用来存储线程 创建一个容量为10的Thread.State数组,用来存储线程状态
*/
Thread[] threads = new Thread[10];
Thread.State[] states = new Thread.State[10];
/*
* 创建一个容量为10的Calculator对象数组,为每个对象都设置不同的数字
* 然后使用它们作为Thread构造器的参数来创建10个线程对象。 将5个线程优先级设置为最高,5个设置为最低
*/
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(new Calculator(i));
if ((i % 2) == 0) {
threads[i].setPriority(Thread.MAX_PRIORITY);
} else {
threads[i].setPriority(Thread.MIN_PRIORITY);
}
threads[i].setName("Thread " + i);
}
/*
* 创建一个PrintWriter对象,用来把线程的状态写入文件
*/
try {
File file = new File("D:\\thread_log.txt");
if(!file.exists()){
file.createNewFile();
}
FileWriter fw = new FileWriter(file);
PrintWriter pw = new PrintWriter(fw);
for (int i = 0; i < 10; i++) {
// System.out.println("Main : Status of Thread " + i + ":" + threads[i].getState());
pw.println("Main : Status of Thread " + i + ":" + threads[i].getState());
states[i] = threads[i].getState();
}
/* 开始执行10个线程 */
for (int i = 0; i < 10; i++) {
threads[i].start();
}
boolean finish = false;
while(!finish){
for(int i = 0;i<10;i++){
if(threads[i].getState() != states[i]){
writeThreadInfo(pw,threads[i],states[i]);
}
}
}
finish = true;
for(int i = 0;i<10;i++){
finish = finish && (threads[i].getState() == State.TERMINATED);
}
pw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void writeThreadInfo(PrintWriter pw, Thread thread, State state) {
// TODO Auto-generated method stub
pw.printf("Main : Id %d - %s\n", thread.getId(),thread.getName());
pw.printf("Main : Priority: %d\n", thread.getPriority());
pw.printf("Main : old State: %s\n", state);
pw.printf("Main :", "***************************\n");
}
}
运行结果
Main : Status of Thread 0:NEW
Main : Status of Thread 1:NEW
Main : Status of Thread 2:NEW
Main : Status of Thread 3:NEW
Main : Status of Thread 4:NEW
Main : Status of Thread 5:NEW
Main : Status of Thread 6:NEW
Main : Status of Thread 7:NEW
Main : Status of Thread 8:NEW
Main : Status of Thread 9:NEW
Main : Id 9 - Thread 0
Main : Priority: 10
Main : old State: NEW
Main :Main : Id 10 - Thread 1
Main : Priority: 1
Main : old State: NEW
Main :Main : Id 11 - Thread 2
Main : Priority: 10
Main : old State: NEW
Main :Main : Id 12 - Thread 3
Main : Priority: 1
Main : old State: NEW
Main :Main : Id 13 - Thread 4
Main : Priority: 10
Main : old State: NEW
Main :Main : Id 14 - Thread 5
Main : Priority: 1
Main : old State: NEW
Main :Main : Id 15 - Thread 6
三、线程的中断
Java提供了线程中断机制,我们可以使用它来结束一个线程。这种机制要求检查它是否被中断了,然后决定是不是响应这个中断请求。线程忽略中断请求并继续执行。我们用isInterrupted()方法来检查线程是否被中断。如果isInterrupted()返回值是true,则表示线程中断了。我们用thread.interrupt()来中断线程。
四、线程的休眠和恢复
通过线程的sleep()方法来打到让线程休眠的状态。线程休眠状态下不占用计算机任何资源。sleep()方法接受×××数值作为参数,表明线程挂起执行的毫秒数。
sleep()方法的另一种使用方式是通过TimeUnit枚举类元素调用。这个方法也使用Thread类的sleep()方法来使当前线程休眠。
五、等待线程的终止
在一些情形下我们必须等待线程的终止。为了达到这个目的,我们使用Thread的join()方法。当一个线程对象的join()方法被调用时,调用它的线程将被挂起,直到这个线程对象完成它的任务。
六、守护线程
Java里有一种特殊的线程叫守护线程(Daemon)。这种线程的优先级很低,通常来说,当同一个应用程序中没有其他线程运行的时候,守护线程才运行。当守护线程是程序中唯一运行的程序时,守护线程执行结束后,JVM也就结束了这个程序。
通常守护线程是无限循环的,以等待服务请求或者执行线程的任务。他们不能做重要的工作,因为我们不可能知道守护线程什么时候能够获取CPU时间片,并且在没有其他线程运行的时候,守护线程随时可能结束。一个典型的守护线程是Java的垃圾回收器(Garbage Collector)。
七、线程的分组
Java提供ThreadGroup类表示一组线程。线程组可以包含线程对象,可以包括其他的线程组对象,它是一个树形结构。相似内容请看Java多线程基础
转载于:https://blog.51cto.com/aku28907/1788953