zoukankan      html  css  js  c++  java
  • Java多线程之线程其他类

    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);
    		}
    	}
    }
    
       
            
  • 相关阅读:
    matplotlib的使用——scatter散点图的绘制
    OpenCVPython系列之立体图像的深度图
    YOLOv3 cfg文件详解
    Opencv的使用小教程2——Opencv常用图像处理函数汇总
    数字世界中的纸张——理解 PDF
    go channel初步
    Unity学习记录 导航
    elasticsearch的keyword与text的区别
    markdownitcontainer
    Windows 编译opensll
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5233096.html
Copyright © 2011-2022 走看看