说起多线程同步是必须要考虑的问题,以前也对同步有所了解,但都处于简单的使用。
这是我们第一想到的是关键字 synchronized,这是我们最通用也是平时程序中处理同步最常见的办法。其使用方法就不用再说了。看看那个声明对象就知道要用该对象的锁进行同步。
或许你还会想起关键字volatile,用来使一个对象读值和写值的同步,但其也有一些不能使用的场景。
此外,我们还会使用object的wait, notice等方法 利用对象锁达到同步的效果,不过这离不开synchronized,因为先要获得锁才能wait。
上面三种是比较常见 和 直接的 同步方法。其实java本身提供给了我们一些实现同步的工具类,其位于 包 java.util.concurrent 下,下面我对这个包下面几个子包的内容作以简单介绍:
- java.util.concurrent:这个包中包含的类为一些高级的同步工具,包含了一些线程的顺序执行,条件执行,线程池等工具,具体使用看看demo
- java.util.concurrent.atomic:这个包中主要是用来来实现一些后来出来的新的CPU支持了compareAndUpdate指令,如果当前CPU不支持该指令会使用锁机制来实现。其下面的AtomicLong和AtomicInteger类在实现计数时非常简单,我们不需要去考虑多线程同步问题。实例代码如下:
public class IdGenerator{private final static AtomicLong creator = new AtomicLong(0);
public static long newId(){return creator .getAndIncrement();}}下面一段是用来更新volatile 字段值的:
public class ReferenceFieldUpdate{private volatile Object obj;
private final AtomicReferenceFieldUpdater<ReferenceFieldUpdate, Object> aUpdate = AtomicReferenceFieldUpdater. newUpdater(ReferenceFieldUpdate. class, Object.class , "obj" );
public void compareAndSet(Object expect, Object update){aUpdate.compareAndSet(this, expect, update);}} - java.util.concurrent.locks:这个包中的一些类,可以自己写一些手动获得对象锁,释放对象锁,使用起来更加灵活。具体例子看看doc中的demo.
在java7 中引入了一下同步工具:
public
class
MaxValueCaculator
{
private
final
ForkJoinPool
pool
=
new
ForkJoinPool(15);
private
final
int
SPLIT_NUM
= 100;
private
class
MaxCaculateTask
extends
RecursiveTask<Long>
{
private
long
datas
[];
private
int
start
;
private
int
end
;
public
MaxCaculateTask(
long
[] datas,
int
start,
int
end)
{
super
();
this
.
datas
= datas;
this
.
start
= start;
this
.
end
= end;
}
@Override
protected
Long compute()
{
long
max = Long.
MIN_VALUE
;
if
(
end
-
start
>
SPLIT_NUM
)
{
int
mid = (
end
+
start
) / 2;
MaxCaculateTask left =
new
MaxCaculateTask(
datas
,
start
, mid);
MaxCaculateTask rigth =
new
MaxCaculateTask(
datas
, mid,
end
);
left.fork();
rigth.fork();
max = Math. max(
max, left.join());
max = Math. max(
max, rigth.join());
}
else
{
for
(
int
i =
start
; i <
end
&& i <
datas
.
length
; i++)
{
max = Math. max(
max,
datas
[i]);
}
}
return
max;
}
}
public
Long caculte(
long
[] datas){
MaxCaculateTask task =
new
MaxCaculateTask(datas, 0, datas.
length
);
return
pool
.invoke(task);
}
public
static
void
main(String[] a){
MaxValueCaculator c=
new
MaxValueCaculator();
long
datas[]=
new
long
[1];
long
cur=System.currentTimeMillis();
for
(
int
i=-111111, j=0;i<11111;i++,j++){
datas[j]=i;
long
temp[]=
new
long
[datas.
length
+1];
System. arraycopy(datas, 0, temp, 0, datas.
length
);
datas=temp;
}
System.
out
.println(System.currentTimeMillis()-cur+
"Ms"
);
cur=System. currentTimeMillis();
System.
out
.println(c.caculte(datas));
System.
out
.println(System.currentTimeMillis()-cur+
"Ms"
);
}
}
- Phaser:也是java7引入的一个解决线程互斥问题的类,该类使用更见灵活,不仅能够实现在某种条件下执行线程的功能还能实现执行达到某个条件停止执行线程的功能。其例子看看http://www.open-open.com/lib/view/open1325208929936.html, 感觉写的还不错。
此外我们对于一些线程级的变量可以使用ThreadLocal类实现。对于每个线程来说使用该类获得的对象是对于线程独立的。
对于多线程产生随机数时,java7中可以使用ThreadLocalRandom 来提高生成效率。