synchronized关键字、Callable以及线程池

[size=medium]Synchronized关键字
从1.0版本开始,Java中的每一个对象都有一个内部锁。
如果一个方法用synchronized关键字生命,那么对象的锁将保护整个方法。也就是说,要调用该方法,线程必须获得内部的对象锁。

换句话说:
public synchronized void method(){
method body
}
等价于
public void method(){
this.intrinsicLock.lock();
try{
method body
}

finally{ this.intrinsicLock.unlock();}
}

必须了解每一个对象有一个内部锁,并且该锁有一个内部条件。由锁来管理那些试图进入synchronized方法的线程,由条件来管理那些调用wait的线程。


将静态方法声明为synchronized也是合法的。如果调用这种方法,该方法获得这个类的内部锁。(注:原文里是“获得类对象的内部锁”,为了避免出现理解误差,此处改为“类的内部锁”)
例如:如果Bank类有一个静态同步的方法,那么该方法被调用时,Bank.class
的锁被锁住。因此,没有其他线程可以调用同一个类的这个或任何其他的同步静态方法。

个人备注:关键在于区别成员方法和类方法的区别。
synchronized的4种用法
1. 方法声明时使用,线程获得的是成员锁.
2. 对某一代码块使用,synchronized后跟括号,括号里是变量,线程获得的是成员锁.
3.synchronized后面括号里是一对象,此时,线程获得的是对象锁.
4.synchronized后面括号里是类,此时,线程获得的是对象锁.

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.


Runnable封装一个异步运行的任务,可以把它想象成为一个没有参数和返回值得异步方法。

Callable和 Runnable 类似,但是有返回值。
Callable接口是一个参数化的类型,只有一个方法call。
public interface Callable<V>{
V call() throws Exception;
}

类型参数是返回值的类型。例如Callable<Integer>表示一个最终返回Integer对象的异步计算。


Future保存异步计算的结果,可以启动一个计算,将Future对象交给某个线程,然后忘掉它。Future对象的所有者在结果计算好之后就可以获得它。

public interface Future<V>{
V get() throws …;
方法被阻塞,直到计算完成。

V get(lont timeout, TimeUnit unit) throws …;
如果在计算完成之前,第二个方法的调用超时,抛出TimeoutException异常。
如果运行计算的线程被中断,则两个get方法都将抛出InterruptedException。

如果计算已经完成,那么get方法立即返回。

void cancel(boolean mayInterrupt);
使用该方法取消该计算,如果计算还未开始,它被取消且不再开始。
如果计算处于运行之中,那么如果参数为true,它就被中断。

boolean isCancelled();如果在任务正常完成前将其取消,则返回true。
boolean isDone();如果在任务已完成,则返回true。
}

public class FutureTask<V>
extends Object
implements Future<V>, Runnable

FutureTask 包装器是一种非常方便的机制,可以将Callable转换成Future 和 Runnable,它同时实现二者的接口


FutureTask(Callable<V> callable)
创建一个 FutureTask,一旦运行就执行给定的 Callable。
FutureTask(Runnable runnable, V result)
创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。


例如:

Callable<Integer> myCall = ……..;
FutureTask<Integer> task = new FutureTask<Integer>(myCall);
Thread t = new Thread(task);// 在这里是一个Runnable
t.start();
….
Integer result = task.get(); //在这里是一个Future


构建一个新的线程是有一定代价的,因为涉及与操作系统的交互。如果程序中创建了大量的生命期很短的线程,应该使用线程池(thread pool).

一个线程池中包含许多准备运行的空闲线程,将Runnable对象交给线程池,就会有一个线程调用run方法。当run方法退出时,线程不会死亡,而是在池中准备为下一个请求提供服务。
另一个使用线程池的理由是减少并发线程的数目。创建大量线程会大大降低性能甚至使虚拟机崩溃。如果有一个会创建许多线程的算法,应该使用一个线程数“固定的”线程池以限制并发线程的总数。

java.util.concurrent
接口 Executor
所有已知子接口:
ExecutorService, ScheduledExecutorService
所有已知实现类:
AbstractExecutorService, ScheduledThreadPoolExecutor, ThreadPoolExecutor


执行器类(Executor)类有许多静态工厂方法用来构建线程池。java.util.concurrent.Executors
public class Executorsextends Object

ExecutorService newCachedThreadPool()
返回一个带缓存的线程池,该池在必要时创建新线程;空闲线程会被保留60秒

ExecutorService newFixedThreadPool(int size)
返回一个线程池,该池包含固定数量的线程;空闲线程会一支被保留

ExecutorService newSingleThreadExecutor
只有一个线程的“池”,该线程顺序执行每一个提交的任务

这三个方法返回实现了ExecutorService接口的ThreadPoolExecutor类的对象。


Java.util.concurrent.ExecutorService
可用下面的方法之一将一个Runnable对象或Callable对象提交给ExecutorService:

Future<?> submit(Runnable task)
返回一个Future<?>可以使用这样的一个对象来调用isDone、cancel或isCancelled。但是,get方法在完成的时候只是简单的返回null。

Future<T> submit(Runnable task, T result)
返回的Future<T>的get方法在完成的时候返回指定的result对象。

Future<T> submit(Callable<T> task)
返回的Future对象将在计算结果准备好的时候得到它。

sutdown()
当用完一个线程池的时候,调用shutdown()方法方法启动该池的关闭序列,被关闭的执行器不再接受新的任务。当所有任务都完成以后,线程池中的线程死亡。

shutdownNow()
该方法取消尚未开始的的所有任务并试图中断正在运行的线程。


下面总结在使用线程池时应该做的事:
调用Executors类中静态的方法 newCachedThreadPool或..
调用submit提交Runnable 或Callable对象
如果想要取消一个任务,或如果提交Callable对象,那就需要保存好返回的Future对象
当不需要提交任何任务时,调用shutdown。


补充:
ScheduleExecutorService newScheduledThreadPool(int size)
用于预定执行而构建的固定线程池,替代java.util.Timer ( Timer用于安排以后
在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。)

ScheduleExecutorService newSingleThreadScheduleExecutor()用于预定执行而构建的单线程“池”[/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值