Java并发学习(一)

1.要响应线程中断

线程接受到中断信号后要及时的对中断进行响应。响应方式:

1.捕捉InterruptException

	for(;;){
		try {
			doXXX();
		} catch (InterruptedException e) {
			System.out.println(getName() +" is interrupt");
			break;
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

2.判断当前线程状态
      	for(;;){
		doXXX();
		//判断是否被中断
		if(Thread.interrupted()){
			System.out.println(getName() +" is interrupt");
			break;
		}
	}

接收到中断信号后,需要结束当前线程,可行的方式有return,break等,比较优雅的方式是抛出InterruptedException异常。代码如下:

public void foo() throws InterruptedException {
    if (Thread.interrupted()) {
        throw new InterruptedException();
    }
}

2.使用ThreadLocal

顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。
  • 不使用ThreadLocal的测试结果
	private int sum2 = 0;
	public int getSum(){
		sum2++;
		return sum2;
	}
	public static void main(String[] args){
		new CurrentTest().threadLocal();
	}
	
	public void threadLocal(){
		TestThreadLocal t1 = new TestThreadLocal(this);
		TestThreadLocal t2 = new TestThreadLocal(this);
		TestThreadLocal t3 = new TestThreadLocal(this);
		t1.setName("t1");
		t2.setName("t2");
		t3.setName("t3");
		t1.start();
		t2.start();
		t3.start();
	}
	class TestThreadLocal extends Thread{
		CurrentTest c;
		public TestThreadLocal(CurrentTest c) {
			this.c = c;
		}
		@Override
		public void run() {
			int sum = this.c.getSum();
			while(sum<10){
				System.out.println(getName()+" sum is "+sum);
				sum = this.c.getSum();
			}
		}
	}
输出结果:出现并发问题
  • 使用ThreadLocal的测试结果
	private ThreadLocal<Integer> sum = new ThreadLocal<Integer>(){
		protected Integer initialValue() {return 0;};
	};
	public int getSum(){
		sum.set(sum.get() + 1);
		return sum.get();
	}
	public static void main(String[] args){
		new CurrentTest().threadLocal();
	}
	
	public void threadLocal(){
		TestThreadLocal t1 = new TestThreadLocal(this);
		TestThreadLocal t2 = new TestThreadLocal(this);
		TestThreadLocal t3 = new TestThreadLocal(this);
		t1.setName("t1");
		t2.setName("t2");
		t3.setName("t3");
		t1.start();
		t2.start();
		t3.start();
	}
	class TestThreadLocal extends Thread{
		CurrentTest c;
		public TestThreadLocal(CurrentTest c) {
			this.c = c;
		}
		@Override
		public void run() {
			int sum = this.c.getSum();
			while(sum<10){
				System.out.println(getName()+" sum is "+sum);
				sum = this.c.getSum();
			}
		}
	}
输出结果:每个线程都从1一直计数到9,线程间没有出现并发问题

事实上ThreadLocal是牺牲空间来减少高并发所消耗的时间,其原理是每个Thread维护一个Map集合,集合的Key是ThreadLocal对象,value是共享变量的副本,这样每次Thread修改变量时就会直接修改本地保存的变量副本。具体ThreadLocal源代码如下:

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
注意:使用ThreadLocal,一般都是声明在静态变量中,如果不断的创建ThreadLocal而且没有调用其remove方法,将会导致内存泄露。

3.任务的提交者和执行者

为了方便并发执行任务,出现了一种专门用来执行任务的实现,也就是Executor。由此,任务提交者不需要再创建管理线程,使用更方便,也减少了开销。
java.util.concurrent.Executors是Executor的工厂类,通过Executors可以创建你所需要的Executor。
常用的子类如下图:(转自:http://blog.csdn.net/qq_29882587/article/details/78658675)
更广泛的使用是ExecutorSevice接口,主要API如下:

其中submit方法可以接收两类参数,Runable和Callable,Callable是需要有返回值的。submit方法返回Feture对象。Feture对象用于线程间的通信,Future通常包括get(阻塞至任务完成), cancel,get(timeout)(等待一段时间)等等。Future也用于异步变同步的场景。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值