除了使用关键字 synchronized 支持的隐式锁(对象的内置锁)外,Concurrency API 支持由 Lock 接口指定的各类显示锁。显示锁能控制更细的粒度,所以也有更好的性能,在逻辑上也比较清晰。安全
标准 JDK中提供了多种显示锁的实现,将在下面的章节中进行介绍异步
直接上代码ide
例子1:性能
public class SyncSameObjectTest1 implements Runnable{this
public void lord1(){.net
try {线程
Thread.sleep(2000);对象
System.out.println("线程:"+Thread.currentThread().getName()+"运行时间:"+System.currentTimeMillis());接口
} catch (Exception e) {get
}
}
//声明显示锁
private Lock lock =new ReentrantLock();
/* 这里将Lock做为线程变量,使得每次建立线程都建立一个Lock对象(对象锁若是不是同一个对象就能异步执行,互不影响)。
* 注意使用Lock锁的时候,必定要包裹在try catch finally里,使得出现运行期异常的时候,锁可以释放!*/
public void run(){
try {
lock.lock();//开始锁定
lord1();
} catch (Exception e) {
}finally{
lock.unlock();//释放锁
}
}
public static void main (String args[]){
try {
ExecutorService eService = Executors.newCachedThreadPool();
System.out.println("任务开始lock显示锁");
for (int i = 0; i < 3; i++) {
eService.submit(new SyncSameObjectTest1());
}
TimeUnit.SECONDS.sleep(10);
System.out.println("任务执行结束");
eService.shutdown();
} catch (Exception e) {
}
}
}
这里采用线程池去启动线程,每次启动线程都是新的线程,从结果能够看到,Lock锁三个线程是异步执行的,相互不影响。形成这种缘由是由于对象是不同的。
改造下试试:
例子2:
public class SyncSameObjectTest1 implements Runnable{
private Lock lock;
public void lord1(){
try {
Thread.sleep(2000);
System.out.println("线程:"+Thread.currentThread().getName()+"运行时间:"+System.currentTimeMillis());
} catch (Exception e) {
}
}
public SyncSameObjectTest1(Lock lock){
this.lock=lock;
}
public SyncSameObjectTest1(){
}
public void run(){
try {
lock.lock();//开始锁定
lord1();
} catch (Exception e) {
lock.unlock();//释放锁
}finally{
lock.unlock();
}
}
public static void main (String args[]){
Lock lock =new ReentrantLock();
try {
ExecutorService eService = Executors.newCachedThreadPool();
System.out.println("任务开始lock显示锁");
for (int i = 0; i < 3; i++) {
eService.submit(new SyncSameObjectTest1(lock));
}
TimeUnit.SECONDS.sleep(10);
System.out.println("任务执行结束");
eService.shutdown();
} catch (Exception e) {
}
}
}
这里在main里面实例化一个锁(或者同一对象调用),线程实例化的时候,将该锁(同一个对象)传进去,已是同步运行了。说明了Lock显式锁是对象锁。看运行顺序及时间可知
任务开始lock显示锁
线程:pool-1-thread-1运行时间:1514537154767
线程:pool-1-thread-2运行时间:1514537156767
线程:pool-1-thread-3运行时间:1514537158767
任务执行结束
当第一个任务获取锁时,第二个任务获取锁的状态信息:
例子3:
lock显示锁 锁用一个对象调用与synchronized隐式锁同一对象结果一致
public class SynchronizedTest {
public static void main(String[] args) {
//线程数
int threadNum = 5;
final Syn syn = new Syn();
Thread[] threads = new Thread[threadNum];
//记录运行时间
long l = System.currentTimeMillis();
for (int i = 0; i < threadNum; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 100000; j++) {
syn.increase();
}
}
});
threads[i].start();
}
//等待全部线程结束
try {
for (int i = 0; i < threadNum; i++)
threads[i].join();
//main线程要等到threads[5]线程运行结束后,才会往下执行输出。若是不加threads[i].join(),
//main线程和threads[i]线程是并行的。而加上threads[i].join(),程序就变成是顺序执行了。
//咱们在用到join()的时候,一般都是main线程等到其余多个线程执行完毕后再继续执行。其余多个线程之间并不须要互相等待。
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(syn + " : " + (System.currentTimeMillis() - l) + "ms");
}
}
class Syn {
private int count = 0;
private Lock lock = new ReentrantLock();
//利用synchronized
public void increase() {
synchronized (this) {
count++;
}
}
//利用ReentrantLock类同步
public void increaseLock() {
lock.lock();
count++;
lock.unlock();
}
//volatile 不是线程安全的 不保证原子性
public void increaseVolatile() {
count = count + 1;
}
@Override public String toString() { return String.valueOf(count); } } 结果:500000 : 20ms