JAVA线程管理

1.线程的创建和运行

继承Thread类,并覆run()方法。创建一个实现runable接口的类。使用带参数的Thread构造器来创建Thread对象。这个参数就是实现runable接口的对象

2.Java线程信息的获取和设置

Thread类有一些保存信息的属性,这些属性可以用来标识线程,显示线程的状态或者控制线程的优先级。

ID:保存了线程的唯一标识。

Name:保存了线程的名称。

Priority:保存率线程对象的优先级.线程的优先级是从1到10,不推荐修改线程的优先级。

Status:保存了线程的状态.在java中有6种:

new:至今尚未启动的线程处于这种状态。

runnable:正在 Java 虚拟机中执行的线程处于这种状态。

blocked:受阻塞并等待某个监视器锁的线程处于这种状态。

wait:无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。

time wait:无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。

terminated:已退出的线程处于这种状态。

3.线程的休眠和恢复

import java.util.Date;
import java.util.concurrent.TimeUnit;
class FileClock implements Runnable{
	@Override
	public void run(){
		for(int i = 0; i < 10; i ++){
			System.out.printf("%s\n",new Date());
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}


}
public class FileMain {
	public static void main(String[] args){
		FileClock clock = new FileClock();
		Thread thread = new Thread(clock);
		thread.start();
		try {
			TimeUnit.SECONDS.sleep(5);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		thread.interrupt();
	}
}

        这个程序每个一秒就会输入实际的时间,接下来是FileClock被中断的信息。当调用sleep()方法后,线程会释放CPU并不在继续执行任务。在这段时间内,线程不在占用CPU时钟,所以CPU可以执行其他的任务。如果休眠张的线程被中断,该方法就会立即抛出InterruptedException异常,而不需要等待到线程休眠时间结束。


3.等待线程的终止


import java.util.Date;
import java.util.concurrent.TimeUnit;
class NetWorkConnectionsLoader implements Runnable{
	public void run(){
		System.out.printf("Beginning data sources loading: %s\n",new Date());
		try{
			TimeUnit.SECONDS.sleep(6);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.printf("Data sources loading has finished: %s\n",new Date());
	}
}

public class DataSourcesLoader implements Runnable{
	@Override
	public void run(){
		System.out.printf("Beginning data sources loading: %s\n",new Date());
		try{
			TimeUnit.SECONDS.sleep(4);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.printf("Data sources loading has finished: %s\n",new Date());
	}
	public static void main(String[] args) {
		DataSourcesLoader dsLoader = new DataSourcesLoader();
		Thread thread1 = new Thread(dsLoader, "DataSourceThread");
		System.out.println("---------------------------");
		NetWorkConnectionsLoader ncLoader = new NetWorkConnectionsLoader();
		Thread thread2 = new Thread(ncLoader, "NetWorkConnectionThread");
		thread1.start();
		thread2.start();
		try {
			thread1.join();
			thread2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.printf("Main : Configuration has been loaded: %s\n",
				new Date());
	}

}

只有当两个线程都结束运行时,主线程对象才开始运行。



4.守护线程。

        守护线程的优先级最低,通常来说,当一个应用程序没有其他的线程运行的时候,守护线程才会运行。当守护线程是程序中唯一运行的线程时,守护线程执行结束后,JVM也就结束了这个程序。

5.线程局部变量的使用

ThreadLocal<T>
get() 返回此线程局部变量的当前线程副本中的值。
initialValue() 返回此线程局部变量的当前线程的“初始值”。
remove() 移除此线程局部变量当前线程的值。
set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值。  
        共享数据时并发程序最核心的问题之一,对于继承Thread类或者实现了runnable接口的对象来说尤其重要,如果创建的对象是实现了Runnable接口的类的实例,用它作为传入参数创建多个线程对象并启动这些线程,那么所有的线程将共享这些属性。也就是说如果你在一个线程中改变了一个属性,所有线程都会别这个改变影响。
在某种情况下,这个对象的属性不需要被所有线程共享。Java并发API提供了一个干净的机制,即线程局部变量(Thread-Local Variable),其具有良好的性能。

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class UnsafeTask implements Runnable{
	private Date startDate;
	@Override
	public void run(){
		startDate = new Date();
		System.out.printf("Starting Thread: %s : %s \n",Thread.currentThread().getId(),startDate);
		try{
			TimeUnit.SECONDS.sleep((int)Math.rint(Math.random()*10));
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.printf("Thread Finished: %s : %s \n",Thread.currentThread().getId(),startDate);
	}
	public static void main(String[] args){
		UnsafeTask task = new UnsafeTask();
		for(int i = 0; i < 10; i++){
			Thread thread = new Thread(task);
			thread.start();
			try{
				TimeUnit.SECONDS.sleep(2);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}
}
运行结果:

Starting Thread: 8 : Thu Dec 18 12:16:05 CST 2014 

Starting Thread: 9 : Thu Dec 18 12:16:07 CST 2014 

Thread Finished: 9 : Thu Dec 18 12:16:07 CST 2014 

Starting Thread: 10 : Thu Dec 18 12:16:09 CST 2014 

Starting Thread: 11 : Thu Dec 18 12:16:11 CST 2014 

Thread Finished: 10 : Thu Dec 18 12:16:11 CST 2014 

Starting Thread: 12 : Thu Dec 18 12:16:13 CST 2014 

Thread Finished: 8 : Thu Dec 18 12:16:13 CST 2014 

Starting Thread: 13 : Thu Dec 18 12:16:15 CST 2014 

Thread Finished: 11 : Thu Dec 18 12:16:15 CST 2014 

Thread Finished: 12 : Thu Dec 18 12:16:15 CST 2014 

Starting Thread: 14 : Thu Dec 18 12:16:17 CST 2014 

Starting Thread: 15 : Thu Dec 18 12:16:19 CST 2014 

Thread Finished: 14 : Thu Dec 18 12:16:19 CST 2014 

Starting Thread: 16 : Thu Dec 18 12:16:21 CST 2014 

Starting Thread: 17 : Thu Dec 18 12:16:23 CST 2014 

Thread Finished: 13 : Thu Dec 18 12:16:23 CST 2014 

Thread Finished: 17 : Thu Dec 18 12:16:23 CST 2014 

Thread Finished: 15 : Thu Dec 18 12:16:23 CST 2014 

Thread Finished: 16 : Thu Dec 18 12:16:23 CST 2014 

这个程序的执行结果。每个现场称都有不同的开始时间,但是当他们结束时,四个线程都有相同的startDate属性。


下面是使用线程局部变量机制来解决这个问题。

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SafeTask implements Runnable {
	private static ThreadLocal<Date> startDate = new ThreadLocal<Date>() {
		protected Date initialValue() {
			return new Date();
		}
	};

	@Override
	public void run() {
		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();
		}
		System.out.printf("Thread Finished: %s : %s \n", Thread.currentThread()
				.getId(), startDate.get());
	}
	public static void main(String[] args){
		SafeTask task = new SafeTask();
		for(int i = 0; i < 10; i++){
			Thread thread = new Thread(task);
			thread.start();
			try{
				TimeUnit.SECONDS.sleep(2);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}

}
运行结果:


Starting Thread: 8: Thu Dec 18 12:49:58 CST 2014

Starting Thread: 9: Thu Dec 18 12:50:00 CST 2014

Starting Thread: 10: Thu Dec 18 12:50:02 CST 2014

Starting Thread: 11: Thu Dec 18 12:50:04 CST 2014

Starting Thread: 12: Thu Dec 18 12:50:06 CST 2014

Thread Finished: 9 : Thu Dec 18 12:50:00 CST 2014 

Thread Finished: 8 : Thu Dec 18 12:49:58 CST 2014 

Starting Thread: 13: Thu Dec 18 12:50:08 CST 2014

Thread Finished: 12 : Thu Dec 18 12:50:06 CST 2014 

Thread Finished: 11 : Thu Dec 18 12:50:04 CST 2014 

Starting Thread: 14: Thu Dec 18 12:50:10 CST 2014

Thread Finished: 10 : Thu Dec 18 12:50:02 CST 2014 

Thread Finished: 13 : Thu Dec 18 12:50:08 CST 2014 

Starting Thread: 15: Thu Dec 18 12:50:12 CST 2014

Thread Finished: 15 : Thu Dec 18 12:50:12 CST 2014 

Starting Thread: 16: Thu Dec 18 12:50:14 CST 2014

Starting Thread: 17: Thu Dec 18 12:50:16 CST 2014

Thread Finished: 17 : Thu Dec 18 12:50:16 CST 2014 

Thread Finished: 14 : Thu Dec 18 12:50:10 CST 2014 

Thread Finished: 16 : Thu Dec 18 12:50:14 CST 2014 

        线程的局部变量分别为每个线程存储了各自的属性,并提供给每个线程使用。可以用get()方法读取这个值,并用set()方法设置这个值。如果线程第一次访问这个变量,线程局部变量可能还没有为他存储值,这个时候initialValue()方法就会被调用,并返回当前时间。

6.线程的分组

        java中提供了一个有趣的功能,它能把线程分组。这允许我们把一个组的线程当成一个单一的单元,对组内线程对象进行访问并操作他们。
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

class Result {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}
public class SearchTask implements Runnable{
	private Result result;
	public SearchTask(Result result){
		this.result = result;
	}
	@Override
	public void run(){
		String name = Thread.currentThread().getName();
		System.out.printf("Thread %s: Start\n", name);
		try{
			doTask();
			result.setName(name);
		}catch(InterruptedException e){
			System.out.printf("Thread %s: Interrupted\n", name);
			return;
		}
		System.out.printf("Thread %s: End",name);
	}
	private void doTask() throws InterruptedException{
		Random random = new Random(new Date().getTime());
		int value = (int)(random.nextDouble()*100);
		System.out.printf("Thread %s: %d\n",Thread.currentThread().getName(),value);
		TimeUnit.SECONDS.sleep(value);
	}
	public static void main(String []args){
		ThreadGroup threadGroup = new ThreadGroup("Searcher");
		Result result = new Result();
		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) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.printf("Number of Thread: %d\n",threadGroup.activeCount());
		System.out.printf("Information about the Thread Group\n");
		threadGroup.list();//获取线程组中包含线程数目。
		Thread[] threads = new Thread[threadGroup.activeCount()];
		threadGroup.enumerate(threads);
		for(int i = 0; i < threadGroup.activeCount(); i++){
			System.out.printf("Thread %s: %s\n",threads[i].getName(),threads[i].getState());
		}
		waitFinish(threadGroup);
		threadGroup.interrupt();
	}
	private static void waitFinish(ThreadGroup threadGroup) {
		// TODO Auto-generated method stub
		while(threadGroup.activeCount()>9){
			try{
				TimeUnit.SECONDS.sleep(1);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}
}

7.使用工厂类创建线程

        工厂模式是面向对象编程中最常见的模式之一。它是一个创建者模式,使用一个类为其他的一个或者多个类创建对象。当我们要为这些类创建对象时,不需要再使用new构造器,而使用工厂类。

使用工厂类,可以将对象的创建集中化,这样做有以下好处:

a.更容易修改类,或者噶彼岸创建对象的方式;

b.更容易为有限资源创建对象的数目。例如我们可以限制一个类型的对象不对于n个。

c.更容易为创建对象的对象生成统计数据。

Java提供了ThreadFactory接口,这个接口实现了线程对象工厂。Java并发API的高级工具类也使用了线程工厂创建线程。

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

class Task implements Runnable{
	@Override
	public void run(){
		try{
			TimeUnit.SECONDS.sleep(1);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}
public class MyThreadFactory implements ThreadFactory{
	private int counter;
	private String name;
	private List<String> stats;
	public MyThreadFactory(String name){
		counter = 0;
		this.name = name;
		stats = new ArrayList<String>();
	}
	@Override
	public Thread newThread(Runnable r){
		Thread t = new Thread(r,name + "-Thread_" + counter);
		counter++;
		stats.add(String.format("Creadted thread %d with name %s on %s\n", t.getId(),
<span style="white-space:pre">	</span>t.getName(),new Date()));
		return t;
	}
	public String getStats(){
		StringBuffer buffer = new StringBuffer();
		Iterator<String> it = stats.iterator();
		while(it.hasNext()){
			buffer.append(it.next());
			buffer.append("\n");
		}
		return buffer.toString();
	}
	public static void main(String[] args){
		MyThreadFactory factory = new MyThreadFactory("MyThreadFactory");
		Task task = new Task();
		Thread thread;
		System.out.printf("Starting thre Threads\n");
		for(int i = 0; i < 10; i++){
			thread = factory.newThread(task);
			thread.start();
		}
		System.out.printf("Factory stats:\n");
		System.out.printf("%s\n",factory.getStats());
	}
}
——————摘自Java7并发编程实战手册(Javier Fernandez Gonzalez)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值