黑马程序员--java多线程加强

------- android培训java培训、期待与您交流! ----------

    继之前的java多线程后,今天我们再来研究下多线程更深一些的东西。

    首先:ThreadLocal,该类提供了线程局部 (thread-local) 变量。也就是说使用这个可以使每一个线程操作的数据的自己线程独有的。以下是一个ThreadLocal的小例子。

    public class TestThreadLocal {
//定义一个存放Integer类型的ThreadLocal
static ThreadLocal<Integer> map = new ThreadLocal<Integer>();
public static void main(String[] args) {
//启动两个线程并在run方法中得到一个随机数
        for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
//打印出当前线程语句和随机数,然后将随机数保存至ThreadLocal
System.out.println(Thread.currentThread().getName()+"is put data "+data);
System.out.println(map.toString());
map.set(data);
//调用TestA和TestB的show方法
new TestA().show();
new TestB().show();
}
}).start();
}
}
//定义两个内部类并获取各自线程的ThreadLocal保存的变量的值,然后打印输出语句
static class TestA{
public void show(){
int number = map.get();
System.out.println("TestA"+Thread.currentThread().getName()+" "+number);
}
}
static class TestB{
public void show(){
int number = map.get();
System.out.println("TestB"+Thread.currentThread().getName()+" "+number);
}
}
}

    下面我们来说说并发线程库,并发线程库里面有很多的类给我提供了已经封装好的同步功能,例如AtomicInteger,AtomicBoolean,AtomicIntegerArray等的Atomic包,还有比较重要的线程池Excutors类,这其中有

Executors.newSingleThreadExecutor();创建单个线程的线程池,Executors.newCachedThreadPool(number);顾名思义,创建number个缓存的线程池,Executors.newScheduledThreadPool(number);创建number个定期或延后运行的线程池等为我们提供了创建多个线程的方法。

    除了上面那些还有Callable,Futrue等类,Callable类似一个带有返回值的Runnable,而Future类似于这个Callable的返回结果,我们来看一个小例子。

ExecutorService service = Executors.newSingleThreadExecutor();
Future<String> future = service.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// TODO Auto-generated method stub
return "Hello World!!";
}
});
System.out.println(future.get());

调用线程的Submit方法并传入Callable,用Future接收,最后打印的future.get()方法就会将call()方法的返回值获得到。

        CompletionService,将生产新的异步任务与使用已完成任务的结果分离开来的服务。我们来看一段小例子。

        //创建一个线程池

ExecutorService service = Executors.newCachedThreadPool();
        //根据线程池创建一个  CompletionService服务并
        CompletionService<Integer> services = new ExecutorCompletionService<Integer>(service);

        //循环十次调用十个线程的Submit方法。
for (int i = 0; i < 10; i++) {
final int seq = i;
services.submit(new Callable<Integer>() {


@Override
public Integer call() throws Exception {
Thread.sleep(new Random().nextInt(5000));
return seq;
}
});
}

                //依次打印上面服务已完成方法的返回结果。
for (int i = 0; i < 10; i++) {
System.out.println(services.take().get());
}

还有一个信号灯类Semaphore,请看下面例子

ExecutorService service = Executors.newCachedThreadPool();
final Semaphore sema = new Semaphore(3);
for (int i = 0; i < 10; i++) {
Runnable runnable = new Runnable() {


@Override
public void run() {
try {
sema.acquire();
System.out.println("路人"
+ Thread.currentThread().getName()
+ "进入了厕所,当前可用坑位"
+ (3 - sema.availablePermits()));
Thread.sleep(new Random().nextInt(10000));
System.out.println("路人"
+ Thread.currentThread().getName() + "即将离开!!");
sema.release();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}
};
service.execute(runnable);

在这里,模拟了一个上厕所的场景,已知厕所坑位就只有信号灯的数量,也就是三个,那么10个线程每次最多只有三个线程可以进入,一旦满了,进入阻塞状态,只有当有线程离开了释放掉了信号灯,才会有下一个线程进入。除了信号灯,还有CountDownLatch以及CyclicBarrier类,前者的适用场合类似模拟跑步发令一样,当裁判的CountDownLatch,CountDown到初始化的数字后,其他线程的运动员就可以起跑比赛了,当所有队员都过终点CountDown后再返回给裁判收取结果,而CyclicBarrier则类似于集合锁一样,当所有线程都运行到了await方法后,就开始继续运行所有进程,结束等待。还有Exchanger类,用于实现两个线程之间的通信交换数据,而且两个线程的交换必须同时进行,否则另一个进入等待。

  除了以上这些还有阻塞队列,例如,BlockingQueue。阻塞队列的put和take方法具有阻塞功能,也就是说,当put后,如果再想put的话,那必须先take掉,有点类似信号灯(Semaphore),但是略有不同。如果你试图向一个已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队列中移除一个元索,将导致线程阻塞,阻塞队列在多线程中有着很好的使用。当然还有同步集合,同步队列,这些在多线程中也都有这很好的运用。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值