LinkinPark
当你的才华撑不起你野心时,那么请潜下心继续学习,心无旁骛,愿多年以后你们我都能成为自己想象的模样。
Java多线程之线程其他类

实际编码中除了前面讲到的常用的类之外,还有几个其他类也有可能用得到,这里来统一整理一下:
1,Callable接口和Future接口
JDK1.5以后提供了上面这2个接口,可以把Callable接口看成Runnable接口的增强版,Callable接口提供call方法作为线程执行体,但是call方法比run方法强大,call方法可以有返回值,call方法可以声明抛出异常。为了获取call方法的返回值,JDK1.5提供了Future接口来代表Callable接口里面call方法的返回值,并提供了一个FutureTask实现类,可以作为Thread类的target。值得注意的是:Callable接口有泛型限制,Callable接口里面的泛型形参类型与call方法返回值类型相同。
具体代码如下:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class LinkinCallable implements Callable<Integer>
{

	@Override
	public Integer call() throws Exception
	{
		int j = 0;
		for (; j < 100; j++)
		{
			System.out.println(Thread.currentThread().getName() + " " + j);
		}
		return j;
	}

	public static void main(String[] args)
	{
		//创建一个Callable对象
		LinkinCallable linkin = new LinkinCallable();
		//包装Callable对象
		FutureTask<Integer> task = new FutureTask<Integer>(linkin);
		for (int i = 0; i < 100; i++)
		{
			System.out.println(Thread.currentThread().getName() + " " + i);
			if (i == 20)
			{
				//用FutureTask作为Thread的target来创建一个线程,然后在启动这个线程
				new Thread(task, "这里的这个线程是有返回值的").start();
			}
		}
		try
		{
			System.out.println(task.get());
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}

}

2,ThreadLocal类
该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。 ThreadLocal是用另外一个角度来解决多线程的并发访问的,它并不是像同步机制那样解决多个线程对相同资源的并发访问,它只是隔离了多个线程之间的共享冲突,每一个线程之间都会有自己的一份资源副本。
具体代码如下:
 
public class Account
{
	//定义一个ThreadLocal类型的变量,该变量将是一个线程局部变量 每个线程都会保留该变量的一个副本
	private ThreadLocal<String> name = new ThreadLocal<String>();

	// 定义一个初始化name属性的构造器
	public Account(String str)
	{
		this.name.set(str);
		// 下面代码用于访问当前线程的name副本的值
		System.out.println("---" + this.name.get());
	}

	// name的setter和getter方法
	public String getName()
	{
		return name.get();
	}

	public void setName(String str)
	{
		this.name.set(str);
	}

	public static void main(String[] args)
	{
		// 启动两条线程,两条线程共享同一个Account
		Account at = new Account("初始名");
		/*
		 * 虽然两条线程共享同一个账户,即只有一个账户名 但由于账户名是ThreadLocal类型的,所以每条线程
		 * 都完全拥有各自的账户名副本,所以从i == 6之后,将看到两条 线程访问同一个账户时看到不同的账户名。
		 */
		new MyTest(at, "线程甲").start();
		new MyTest(at, "线程乙").start();
	}
}

class MyTest extends Thread
{
	// 定义一个Account属性
	private Account account;

	public MyTest(Account account, String name)
	{
		super(name);
		this.account = account;
	}

	public void run()
	{
		// 循环10次
		for (int i = 0; i < 10; i++)
		{
			// 当i == 6时输出将账户名替换成当前线程名
			if (i == 6)
			{
				account.setName(getName());
			}
			// 输出同一个账户的账户名和循环变量
			System.out.println(account.getName() + " 账户的i值:" + i);
		}
	}
}
   
        
posted on 2015-02-05 15:08  LinkinPark  阅读(179)  评论(0编辑  收藏  举报