From Evernote: |
找回删除的文件Clipped from: http://weibo.com/mamashuowodezuichang?leftnav=1&wvr=5 |
对酒当歌,人生几何? 譬如朝露,去日苦多。 慨当以慷,忧思难忘。 何以解忧,唯有杜康。 青青子衿,悠悠我心。 但为君故,沉吟至今。 呦呦鹿鸣,食野之苹。 我有嘉宾,鼓瑟吹笙。 明明如月,何时可掇。 忧从中来,不可断绝。 越陌度阡,枉用相存。 契阔谈宴,心念旧恩。 月明星稀,乌鹊南飞。 绕树三匝,何枝可依? 山不厌高,海不厌深。 周公吐哺,天下归心。
2013年5月23日星期四
2013年5月10日星期五
java泛型通配符-协变与逆变
From Evernote: |
java泛型通配符-协变与逆变Clipped from: http://arron-li.iteye.com/blog/673783 |
周末研究了下java泛型,关于泛型通配符的协变与逆变问题,题目如下:
- 题目要求:创建一个泛型类Generic1<T>,它只有一个方法,将接受一个T类型的参数。创建第二个泛型类Generic2<T>,它也只有一个方法,将返回类型T的参数。编写一个泛型方法,它具有一个调用第一个泛型类的方法的逆变参数。编写第二个泛型方法,它具有一个调用第二个泛型类的方法的协变参数。
- 实例代码如下:
- package generics.exercises;
- import java.util.ArrayList;
- import java.util.List;
- import typeinfo.pets.Dog;
- public class ContraVarianceAndCovariant {
- static class Generic1Sup<T> {
- }
- static class Generic1<T> extends Generic1Sup<T> {
- void setT(T t) {
- }
- }
- static class Generic1Sub<T> extends Generic1<T> {
- }
- static class Generic2Sup<T> {
- }
- static class Generic2<T> extends Generic2Sup<T> {
- T getT(T t) {
- return t;
- }
- }
- static class Generic2Sub<T> extends Generic2<T> {
- }
- static <T> void writeWithWildcard(List<? super T> list, T item) {
- list.add(item);
- }
- static <T> T readCovariant(List<? extends T> list) {
- return list.get(0);
- }
- static List<Generic1<Dog>> dogs = new ArrayList<Generic1<Dog>>();
- static List<Generic1Sup<Dog>> dogsSup = new ArrayList<Generic1Sup<Dog>>();
- static List<Generic1Sub<Dog>> dogsSub = new ArrayList<Generic1Sub<Dog>>();
- static List<Generic2<Dog>> dogs2 = new ArrayList<Generic2<Dog>>();
- static List<Generic2Sup<Dog>> dogs2Sup = new ArrayList<Generic2Sup<Dog>>();
- static List<Generic2Sub<Dog>> dogs2Sub = new ArrayList<Generic2Sub<Dog>>();
- static void f1() {
- writeWithWildcard(dogs, new Generic1<Dog>());
- writeWithWildcard(dogsSup, new Generic1<Dog>());
- // ! writeWithWildcard(dogsSub, new Generic1<Dog>());
- Generic1<Dog> generic1 = dogs.get(0);
- generic1.setT(new Dog("dog1"));
- System.out.println(generic1);
- }
- static void f2() {
- Generic2<Dog> generic2 = readCovariant(dogs2);
- generic2 = (Generic2<Dog>) readCovariant(dogs2Sup);
- generic2 = readCovariant(dogs2Sub);
- generic2.getT(new Dog("dog2"));
- System.out.println(generic2);
- }
- static class CovariantReader<T> {
- T readCovariant(List<? extends T> list) {
- return list.get(0);
- }
- }
- static void f3() {
- CovariantReader<Generic2<Dog>> fruitReader = new CovariantReader<Generic2<Dog>>();
- Generic2<Dog> generic2 = fruitReader.readCovariant(dogs2);
- // ! generic2 = fruitReader.readCovariant(dogs2Sup);
- generic2 = fruitReader.readCovariant(dogs2Sub);
- generic2.getT(new Dog("dog2"));
- }
- }
感兴趣的读者可以研究下,为题目提供更好的解决方案。
2013年5月7日星期二
java并发编程中CountDownLatch和CyclicBarrier的使用 - [java]
From Evernote: |
java并发编程中CountDownLatch和CyclicBarrier的使用 - [java]Clipped from: http://blackgu.blogbus.com/logs/69596661.html |
java并发编程中CountDownLatch和CyclicBarrier的使用 - [java]
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://blackgu.blogbus.com/logs/69596661.html
在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决?
如果是一个线程等待一个线程,则可以通过await()和notify()来实现;
如果是一个线程等待多个线程,则就可以使用CountDownLatch和CyclicBarrier来实现比较好的控制。
下面来详细描述下CountDownLatch的应用场景:
例如:百米赛跑:8名运动员同时起跑,由于速度的快慢,肯定有会出现先到终点和晚到终点的情况,而终点有个统计成绩的仪器,当所有选手到达终点时,它会统计所有人的成绩并进行排序,然后把结果发送到汇报成绩的系统。
其实这就是一个CountDownLatch的应用场景:一个线程或多个线程等待其他线程运行达到某一目标后进行自己的下一步工作,而被等待的"其他线程"达到这个目标后继续自己下面的任务。
这个场景中:
1. 被等待的"其他线程"------>8名运动员
2. 等待"其他线程"的这个线程------>终点统计成绩的仪器
那么,如何来通过CountDownLatch来实现上述场景的线程控制和调度呢?
jdk中CountDownLatch类有一个常用的构造方法:CountDownLatch(int count);
两个常用的方法:await()和countdown()
其中count是一个计数器中的初始化数字,比如初始化的数字是2,当一个线程里调用了countdown(),则这个计数器就减一,当线程调用了await(),则这个线程就等待这个计数器变为0,当这个计数器变为0时,这个线程继续自己下面的工作。下面是上述CountDownLatch场景的实现:
Work类(运动员):
import java.util.concurrent.CountDownLatch;
public class Work implements Runnable {
private int id;
private CountDownLatch beginSignal;
private CountDownLatch endSignal;
public Work(int id, CountDownLatch begin, CountDownLatch end) {
this.id = id;
this.beginSignal = begin;
this.endSignal = end;
}
@Override
public void run() {
try {
beginSignal.await();
System.out.println("起跑...");
System.out.println("work" + id + "到达终点");
endSignal.countDown();
System.out.println("work" + id + "继续干其他事情");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Main类(终点统计仪器):
import java.util.concurrent.CountDownLatch;
public class Main {
public static void main(String[] args) {
CountDownLatch begSignal = new CountDownLatch(1);
CountDownLatch endSignal = new CountDownLatch(8);
for (int i = 0; i < 8; i++) {
new Thread(new Work(i, begSignal, endSignal)).start();
}
try {
begSignal.countDown(); //统一起跑
endSignal.await(); //等待运动员到达终点
System.out.println("结果发送到汇报成绩的系统");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
下面详细描述下CyclicBarrier的应用场景:
有四个游戏玩家玩游戏,游戏有三个关卡,每个关卡必须要所有玩家都到达后才能允许通关。
其实这个场景里的玩家中如果有玩家A先到了关卡1,他必须等待其他所有玩家都到达关卡1时才能通过,也就是说线程之间需要互相等待,这和CountDownLatch的应用场景有区别,CountDownLatch里的线程是到了运行的目标后继续干自己的其他事情,而这里的线程需要等待其他线程后才能继续完成下面的工作。
jdk中CyclicBarrier类有两个常用的构造方法:
1. CyclicBarrier(int parties)
这里的parties也是一个计数器,例如,初始化时parties里的计数是3,于是拥有该CyclicBarrier对象的线程当parties的计数为3时就唤醒,注:这里parties里的计数在运行时当调用CyclicBarrier:await()时,计数就加1,一直加到初始的值
2. CyclicBarrier(int parties, Runnable barrierAction)
这里的parties与上一个构造方法的解释是一样的,这里需要解释的是第二个入参(Runnable barrierAction),这个参数是一个实现Runnable接口的类的对象,也就是说当parties加到初始值时就出发barrierAction的内容。
下面来实现上述的应用场景:
Player类(玩家类)
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Player implements Runnable {
private CyclicBarrier cyclicBarrier;
private int id;
public Player(int id, CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
this.id = id;
}
@Override
public void run() {
try {
System.out.println("玩家" + id + "正在玩第一关...");
cyclicBarrier.await();
System.out.println("玩家" + id + "进入第二关...");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
GameBarrier类(关卡类,这里控制玩家必须全部到达第一关结束的关口才能进入第二关)
import java.util.concurrent.CyclicBarrier;
public class GameBarrier {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(4, new Runnable() {
@Override
public void run() {
System.out.println("所有玩家进入第二关!");
}
});
for (int i = 0; i < 4; i++) {
new Thread(new Player(i, cyclicBarrier)).start();
}
}
}
Java CountDownLatch应用
From Evernote: |
Java CountDownLatch应用Clipped from: http://zapldy.iteye.com/blog/746458 |
Java的concurrent包里面的CountDownLatch其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。
你可以向CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。
CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。
举个例子,有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:
- package org.zapldy.concurrent;
- import java.util.Random;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.TimeUnit;
- public class Worker implements Runnable{
- private CountDownLatch downLatch;
- private String name;
- public Worker(CountDownLatch downLatch, String name){
- this.downLatch = downLatch;
- this.name = name;
- }
- public void run() {
- this.doWork();
- try{
- TimeUnit.SECONDS.sleep(new Random().nextInt(10));
- }catch(InterruptedException ie){
- }
- System.out.println(this.name + "活干完了!");
- this.downLatch.countDown();
- }
- private void doWork(){
- System.out.println(this.name + "正在干活!");
- }
- }
- package org.zapldy.concurrent;
- import java.util.concurrent.CountDownLatch;
- public class Boss implements Runnable {
- private CountDownLatch downLatch;
- public Boss(CountDownLatch downLatch){
- this.downLatch = downLatch;
- }
- public void run() {
- System.out.println("老板正在等所有的工人干完活......");
- try {
- this.downLatch.await();
- } catch (InterruptedException e) {
- }
- System.out.println("工人活都干完了,老板开始检查了!");
- }
- }
- package org.zapldy.concurrent;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class CountDownLatchDemo {
- public static void main(String[] args) {
- ExecutorService executor = Executors.newCachedThreadPool();
- CountDownLatch latch = new CountDownLatch(3);
- Worker w1 = new Worker(latch,"张三");
- Worker w2 = new Worker(latch,"李四");
- Worker w3 = new Worker(latch,"王二");
- Boss boss = new Boss(latch);
- executor.execute(w3);
- executor.execute(w2);
- executor.execute(w1);
- executor.execute(boss);
- executor.shutdown();
- }
- }
当你运行CountDownLatchDemo这个对象的时候,你会发现是等所有的工人都干完了活,老板才来检查,下面是我本地机器上运行的一次结果,可以肯定的每次运行的结果可能与下面不一样,但老板检查永远是在后面的。
好了,就写到这里,睡觉去了!
2013年5月6日星期一
AtomicInteger
From Evernote: |
AtomicIntegerClipped from: http://blog.csdn.net/sunnydogzhou/article/details/6564396 |
AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
来看AtomicInteger提供的接口。
//获取当前的值
public final int get()
//取当前的值,并设置新的值
public final int getAndSet(int newValue)
//获取当前的值,并自增
public final int getAndIncrement()
//获取当前的值,并自减
public final int getAndDecrement()
//获取当前的值,并加上预期的值
public final int getAndAdd(int delta)
... ...
我们在上一节提到的CAS主要是这两个方法
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
这两个方法是名称不同,但是做的事是一样的,可能在后续的java版本里面会显示出区别来。
详细查看会发现,这两个接口都是调用一个unsafe的类来操作,这个是通过JNI实现的本地方法,细节就不考虑了。
下面是一个对比测试,我们写一个synchronized的方法和一个AtomicInteger的方法来进行测试,直观的感受下性能上的差异
- package zl.study.concurrency;
- import java.util.concurrent.atomic.AtomicInteger;
- public class AtomicIntegerCompareTest {
- private int value;
- public AtomicIntegerCompareTest(int value){
- this.value = value;
- }
- public synchronized int increase(){
- return value++;
- }
- public static void main(String args[]){
- long start = System.currentTimeMillis();
- AtomicIntegerCompareTest test = new AtomicIntegerCompareTest(0);
- for( int i=0;i< 1000000;i++){
- test.increase();
- }
- long end = System.currentTimeMillis();
- System.out.println("time elapse:"+(end -start));
- long start1 = System.currentTimeMillis();
- AtomicInteger atomic = new AtomicInteger(0);
- for( int i=0;i< 1000000;i++){
- atomic.incrementAndGet();
- }
- long end1 = System.currentTimeMillis();
- System.out.println("time elapse:"+(end1 -start1) );
- }
- }
结果
time elapse:31
time elapse:16
由此不难看出,通过JNI本地的CAS性能远超synchronized关键字
Reference
http://stackoverflow.com/questions/2443239/java-atomicinteger-what-are-the-differences-between-compareandset-and-weakcompar