论坛首页 Java企业应用论坛

说一说java的concurrent包-系列文章

浏览 20693 次
精华帖 (6) :: 良好帖 (5) :: 新手帖 (13) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-03-30  
核桃博客 写道
说一说java的concurrent包4--可以代替synchronized关键字的ReentrantLock
http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E7%9A%84concurrent%E5%8C%854-%E5%8F%AF%E4%BB%A5%E4%BB%A3%E6%9B%BFsynchronized%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84reentrantlock/
在jdk 1.4时代,线程间的同步主要依赖于synchronized关键字,本质上该关键字是一个对象锁,可以加在不同的instance上或者class上,从使用的角度则分别可以加在非静态方法,静态方法,以及直接synchronized(MyObject)这样的用法;
concurrent包提供了一个可以替代synchronized关键字的ReentrantLock,
简单的说你可以new一个ReentrantLock, 然后通过lock.lock和lock.unlock来获取锁和释放锁;注意必须将unlock放在finally块里面,
reentrantlock的好处
1. 是更好的性能,
2. 提供同一个lock对象上不同condition的信号通知
3. 还提供lockInterruptibly这样支持响应中断的加锁过程,意思是说你试图去加锁,但是当前锁被其他线程hold住,然后你这个线程可以被中断;

简单的一个例子:

package com.hetaoblog.concurrent.test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

import org.junit.Test;

public class ReentrantLockDemo {

	@Test
	public void demoLock()
	{
		final int loopcount = 10000;
		int threadcount = 10;

		final SafeSeqWithLock seq = new SafeSeqWithLock();

		final CountDownLatch l = new CountDownLatch(threadcount);

		for(int i = 0; i < threadcount; ++i)
		{
			final int index = i;
			new Thread(new Runnable() {

				@Override
				public void run() {
					for(int j = 0; j < loopcount; ++j)
					{

						seq.inc();

					}

					System.out.println("finished : " + index);
					l.countDown();

				}
			}).start();
		}

		try {
			l.await();
		} catch (InterruptedException e) {

			e.printStackTrace();
		}

		System.out.println("both have finished....");

		System.out.println("SafeSeqWithLock:" + seq.get());

	}
}

class SafeSeqWithLock{
	private long count = 0;

	private ReentrantLock lock = new ReentrantLock();

	public void inc()
	{
		lock.lock();

		try{
			count++;
		}
		finally{
			lock.unlock();
		}
	}

	public long get()
	{
		return count;
	}
}


同样以前面的类似Sequence的类举例,通过对inc操作加锁,保证了线程安全;
当然,这里get()我没有加锁,对于这样直接读取返回原子类型的函数,我认为不加锁是没问题的,相当于返回最近成功操作的值;

运行结果类似这样,
finished : 7
finished : 2
finished : 6
finished : 1
finished : 5
finished : 3
finished : 0
finished : 9
finished : 8
finished : 4
both have finished....
SafeSeqWithLock:100000



这一段是肯定有问题的,返回get没有sync那必然会出错
很明显就看出来你只有一个线程在get...你多加几个线程来执行
final SafeSeqWithLock seq = new SafeSeqWithLock(); seq.inc();  就会发现问题了,但是用原子操作的话,get也就不需要同步了..试试看. ^_^
0 请登录后投票
   发表时间:2012-03-30   最后修改:2012-03-30
强烈建议说下AbstractQueuedSynchronizer的原理以及线程安全问题(主要是可见性问题)

我有浓烈兴趣
0 请登录后投票
   发表时间:2012-03-30  
天籁の圁 写道
核桃博客 写道
说一说java的concurrent包4--可以代替synchronized关键字的ReentrantLock
http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E7%9A%84concurrent%E5%8C%854-%E5%8F%AF%E4%BB%A5%E4%BB%A3%E6%9B%BFsynchronized%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84reentrantlock/
在jdk 1.4时代,线程间的同步主要依赖于synchronized关键字,本质上该关键字是一个对象锁,可以加在不同的instance上或者class上,从使用的角度则分别可以加在非静态方法,静态方法,以及直接synchronized(MyObject)这样的用法;
concurrent包提供了一个可以替代synchronized关键字的ReentrantLock,
简单的说你可以new一个ReentrantLock, 然后通过lock.lock和lock.unlock来获取锁和释放锁;注意必须将unlock放在finally块里面,
reentrantlock的好处
1. 是更好的性能,
2. 提供同一个lock对象上不同condition的信号通知
3. 还提供lockInterruptibly这样支持响应中断的加锁过程,意思是说你试图去加锁,但是当前锁被其他线程hold住,然后你这个线程可以被中断;

简单的一个例子:

package com.hetaoblog.concurrent.test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

import org.junit.Test;

public class ReentrantLockDemo {

	@Test
	public void demoLock()
	{
		final int loopcount = 10000;
		int threadcount = 10;

		final SafeSeqWithLock seq = new SafeSeqWithLock();

		final CountDownLatch l = new CountDownLatch(threadcount);

		for(int i = 0; i < threadcount; ++i)
		{
			final int index = i;
			new Thread(new Runnable() {

				@Override
				public void run() {
					for(int j = 0; j < loopcount; ++j)
					{

						seq.inc();

					}

					System.out.println("finished : " + index);
					l.countDown();

				}
			}).start();
		}

		try {
			l.await();
		} catch (InterruptedException e) {

			e.printStackTrace();
		}

		System.out.println("both have finished....");

		System.out.println("SafeSeqWithLock:" + seq.get());

	}
}

class SafeSeqWithLock{
	private long count = 0;

	private ReentrantLock lock = new ReentrantLock();

	public void inc()
	{
		lock.lock();

		try{
			count++;
		}
		finally{
			lock.unlock();
		}
	}

	public long get()
	{
		return count;
	}
}


同样以前面的类似Sequence的类举例,通过对inc操作加锁,保证了线程安全;
当然,这里get()我没有加锁,对于这样直接读取返回原子类型的函数,我认为不加锁是没问题的,相当于返回最近成功操作的值;

运行结果类似这样,
finished : 7
finished : 2
finished : 6
finished : 1
finished : 5
finished : 3
finished : 0
finished : 9
finished : 8
finished : 4
both have finished....
SafeSeqWithLock:100000



这一段是肯定有问题的,返回get没有sync那必然会出错
很明显就看出来你只有一个线程在get...你多加几个线程来执行
final SafeSeqWithLock seq = new SafeSeqWithLock(); seq.inc();  就会发现问题了,但是用原子操作的话,get也就不需要同步了..试试看. ^_^


想了下,可能的确不对,加上volatile应该就可以
0 请登录后投票
   发表时间:2012-03-30  
freish 写道
强烈建议说下AbstractQueuedSynchronizer的原理以及线程安全问题(主要是可见性问题)

我有浓烈兴趣


好的,下次会慢慢加上的,多谢关注:)
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics