线程管理
1、 线程的创建和运行
a) 线程的创建有两种方法,继承Thread类或者事项Runnable接口
示例:
package lwl;
/*
* 创建线程类实现接口Runnable
*/
public classCreateThread implements Runnable {
private static final int SIZE = 10;
private int number;
public CreateThread(int number) {
this.number = number;
}
/**
* 实现Runnable接口里的run方法
*/
@Override
public void run() {
for (int i = 0; i < SIZE; i++) {
System.out.println(Thread.currentThread().getName()+
" : " + number + " * " + i + " = " + i * number);
}
}
}
主程序:
package lwl;
public classMain {
private static final int SIZE = 10;
public static void main(String[] args) {
for (int i = 0; i < SIZE; i++) {
CreateThreadcreateThread= newCreateThread(i);
//创建thread对象,这个对象时createThread
Threadthread= newThread(createThread);
//启动线程
thread.start();
}
}
}
2、 线程信息的获取和设置
a) Thread类有一些保存信息的属性,这些属性可以用来标示线程,显示线程的状态或者控制线程的优先级
b) 线程有6中状态:new 、runnable、blocked、waiting、time waiting或terminated
示例:
package lwl;
/*
* 创建线程类实现接口Runnable
*/
public classCreateThread implements Runnable {
private static final int SIZE = 10;
private int number;
public CreateThread(int number) {
this.number = number;
}
/**
* 实现Runnable接口里的run方法
*/
@Override
public void run() {
for (int i = 0; i < SIZE; i++) {
System.out.println(Thread.currentThread().getName()+
" : " + number + " * " + i + " = " + i * number);
}
}
}
package lwl;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.lang.Thread.State;
public classMain {
private static final int SIZE = 10;
public static void main(String[] args) {
// 创建一个线程组,线程数目为10,State表示线程的状态
Threadthreads[]= newThread[SIZE];
Thread.Statestatus[]= newThread.State[10];
// 设置线程的优先级
for (int i = 0; i < SIZE; i++) {
threads[i] = new Thread(new CreateThread(i));
if ((i % 2) == 0) {
threads[i].setPriority(Thread.MAX_PRIORITY);
}else{
threads[i].setPriority(Thread.MIN_PRIORITY);
}
threads[i].setName("Thread"+ i);
}
// 把线程状态写入到log.txt文件
try {
FileWriterfile= newFileWriter("..\\data\\log.txt");
PrintWriterpw = new PrintWriter(file);
for (int i = 0; i < SIZE; i++) {
pw.println("Main : Status of Thread " + i + " : " + threads[i].getState());
status[i] = threads[i].getState();
}
boolean finish = false;
while (!finish) {
for (int i = 0; i < SIZE; i++) {
if (threads[i].getState() != status[i]) {
writerThreadInfo(pw, threads[i], status[i]);
status[i] = threads[i].getState();
}
}
finish = true;
for (int i = 0; i < SIZE; i++) {
finish = finish && (threads[i].getState() == State.TERMINATED);
}
}
}catch(Exception e) {
// TODO: handle exception
}
// 开始执行线程
for (int i = 0; i < SIZE; i++) {
threads[i].start();
}
}
private static voidwriterThreadInfo(PrintWriter pw, Thread thread,State state){
pw.println("Main : Id "+thread.getId()+ " - "+ thread.getName());
pw.println("Main : Priority "+thread.getPriority());
pw.println("Main : Old State: "+ state);
pw.println("Main : New State "+thread.getState());
pw.println("Main : **************************************");
}
}
3、 线程的中断
a) Java提供中断机制,可以使用它来结束一个线程。这种机制需要检查线程是否被中断,然后决定是否响应这个中断请求,线程允许中断请求并继续执行
示例:
package lwl;
public classPrimeGenerator extends Thread{
@Override
public void run(){
long number =1L;
while(true){
if(isPrime(number)){
System.out.println(number + " is Prime");
}
//isInterrupte()检查线程是否被中断,如果isInterrupted()返回值为true,就写一个信息并且结束线程的执行 if(isInterrupted()){
System.out.println("The Prime Generator has been Interrupted");
return;
}
number ++;
}
}
//如果number是一个质数,那么返回值为true,否则返回值为false
private boolean isPrime(long number) {
if(number <= 2){
return true;
}
for(long i = 2; i < number; i++){
if((number % i) == 2){
return false;
}
}
return true;
}
}
package lwl;
public classMain1 {
public static void main(String[] args) {
//创建PrimeGenerator类的一个对象,并且执行运行这个线程对象
Threadthread= newPrimeGenerator();
thread.start();
try {
Thread.sleep(5000);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//中断这个线程对象
thread.interrupt();
}
}
Thread类有一个表明线程被中断与否的属性,它存放的就布尔值。线程的interrupt()方法被调用时,这个属性就会被设置为true,isInterrupter()方法只是这个属性的值。
Thread类的静态方法interrupt()也可以来检查当前执行的线程是否被中断。
isInterrupted()和interrupted()方法有个很大的区别,isInterrupted()不能改变interrupted属性的值,但是后者能设置interrupted的值为false。应为interrupted()时一个静态方法,更推荐使用isInterrupted()方法。
4、 线程中断控制
a) 使用Java异常InterruptedException()来控制控制。
示例:
package lwl;
import java.io.File;
public classFileSearch implementsRunnable {
private String initPath;
private String fileName;
public FileSearch(String initPath, String fileName) {
this.initPath = initPath;
this.fileName = fileName;
}
// 实现run()方法,查找文件名
@Override
public void run() {
Filefile= newFile(initPath);
// file.isDirectory()如果返回值为true这表示这个initPath时一个目录
if (file.isDirectory()) {
try {
directoryProcess(file);
}catch(InterruptedException e) {
System.out.println(Thread.currentThread().getName()+ " : The search has been interrupted.");
}
}
}
private void directoryProcess(File file) throws InterruptedException {
Filelist[]= file.listFiles();
if (list != null) {
for (int i = 0; i < list.length; i++) {
if (list[i].isDirectory()) {
directoryProcess(list[i]);
}else{
fileProcess(list[i]);
}
}
}
// 检查这个方法是否被中断,如果被中断就抛出InterruptedException()异常
if (Thread.interrupted()){
throw new InterruptedException();
}
}
// 比对当前文件的文件名和要查找的文件是否匹配,如果匹配就打印到控制台,做完比较后,检查线程是否被中断,
// 如果时将抛出InterruptedException异常
private void fileProcess(File file) throws InterruptedException {
if (file.getName().equals(fileName)) {
System.out.println(Thread.currentThread().getName()+ " : "+ file.getAbsolutePath());
}
// 检查这个方法是否被中断,如果被中断就抛出InterruptedException()异常
if (Thread.interrupted()){
throw new InterruptedException();
}
}
}
package lwl;
import java.util.concurrent.TimeUnit;
public classMain2 {
public static void main(String[] args) {
FileSearchfileSearch= newFileSearch("C:\\","log_network.txt");
Threadthread= newThread(fileSearch);
thread.start();
try {
TimeUnit.SECONDS.sleep(10);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
thread.interrupt();
}
}
5、 线程的休眠和恢复
a) 使用sleep()方法控制线程休眠
示例:
package lwl;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import javax.print.attribute.Size2DSyntax;
public classFileClock implements Runnable{
private static final int SIZE = 10;
@Override
public void run() {
for (int i = 0; i < SIZE; i++) {
System.out.println(new Date());
try {
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedException e) {
System.out.println("The FileClock has been Interrupted");
}
}
}
}
package lwl;
import java.util.concurrent.TimeUnit;
public classMain3 {
public static void main(String[] args) {
Threadthread= newThread(newFileClock());
thread.start();
try {
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//中断线程
thread.interrupt();
}
}
6、 等待线程的终止
a) Java中使用Thread类里的join()方法实现线程终止。当一个线程对象的join()方法被调用时,,调用它的线程将被挂起,直到这个线程对象完成它的任务。
示例:
package lwl;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public classDataSourceLoader implements Runnable {
@Override
public void run() {
System.out.println("Beggining data Source loading: " + newDate());
try {
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Data source loading has finished: " + newDate());
}
}
package lwl;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public classNewworkConnectionsLoader implements Runnable {
@Override
public void run() {
System.out.println("Beggining data Source loading: " + newDate());
try {
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Data source loading has finished: " + newDate());
}
}
package lwl;
import java.util.Date;
public classMain4 {
public static void main(String[] args) {
DataSourceLoaderdataSourceLoader= newDataSourceLoader();
Threadthread1= newThread(dataSourceLoader,"DataSourceLoader");
NewworkConnectionsLoadernewworkConnectionsLoader = newNewworkConnectionsLoader();
Threadthread2 = newThread(newworkConnectionsLoader,"NewworkConnectionsLoader");
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Main :Configuration has been loaded: "+newDate());
}
}
如果不加等待线程join()方法,则会打印主函数里的信息
也可以给join加上时间的控制:例如thread1.join(5000)
7、 守护线程的创建和运行
a) Java有一种特殊的线程叫守护线程。这种线程优先级比较低,通常来说,当同一个应用程序里没有其他线程运行的时候,守护线程才运行。当守护线程时程序中唯一运行的线程时,守护线程执行结束后,JVM也就结束了这个线程
示例:
package lwl;
import java.util.concurrent.TimeUnit;
public classSetDaemonThread implements Runnable {
@Override
public void run() {
// 一直循环
for (int i = 0;; i++) {
try {
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package lwl;
import java.io.IOException;
public classMain5 {
public static void main(String[] args) {
SetDaemonThreadsetTest= newSetDaemonThread();
Threadthread= newThread(setTest);
//设置为守护线程
thread.setDaemon(true);//如果设置成false则是个死循环,没有退出条件,设置为true,即可主线程结束,
thread.start();
System.out.println("isDaemon = "+thread.isDaemon());
try {
System.in.read();
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
8、 线程局部变量的使用
a) 共享数据是并发程序最核心的问题之一,对于继承Thread类或者实现Runnable接口对象来说尤其重要
b) Java提供一个线程局部变量来控制线程变量的值
示例:
package lwl;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public classUnsafeTask implementsRunnable {
// 使用ThreadLocal类控制线程中变量
private static ThreadLocal<Date>startDate= newThreadLocal<Date>() {
protected DateinitialValue() {
return new Date();
}
};
@Override
public void run() {
System.out.println("Starting Thread: "+ Thread.currentThread().getId() + startDate.get());
try {
TimeUnit.SECONDS.sleep((int) Math.rint(Math.random()* 10));
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Thread Finished: "+ Thread.currentThread().getId() + startDate.get());
}
}
package lwl;
import java.util.concurrent.TimeUnit;
public classMain6 {
public static void main(String[] args) {
UnsafeTaskunsafeTask= newUnsafeTask();
for (int i = 0; i < 10; i++) {
Threadthread= newThread(unsafeTask);
thread.start();
try {
TimeUnit.SECONDS.sleep(2);
}catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
线程局部变量分别为每个线程存储了各自的属性值,并提供给每个线程使用。你可以使用get()方法读取这个值,并用set()方法设置这个值。如果线程是第一次访问线程局部变量,线程局部变量可能还没有为它存储值,这个时候initialValue()方法就会被调用,并且返回当前的时间值。