1.线程的创建和运行
继承Thread类,并覆run()方法。创建一个实现runable接口的类。使用带参数的Thread构造器来创建Thread对象。这个参数就是实现runable接口的对象2.Java线程信息的获取和设置
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.线程局部变量的使用
get() 返回此线程局部变量的当前线程副本中的值。initialValue() 返回此线程局部变量的当前线程的“初始值”。remove() 移除此线程局部变量当前线程的值。set(T value) 将此线程局部变量的当前线程副本中的值设置为指定值。
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.线程的分组
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)