Java并发学习(一)

来源:互联网 发布:日本社交软件 编辑:程序博客网 时间:2024/05/22 11:40

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;}@Overridepublic 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;}@Overridepublic 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也用于异步变同步的场景。

原创粉丝点击