同步的方法:
1.Java 同步关键字(synchronized)
- 实例方法
实例方法同步是同步在拥有该方法的对象上。
public synchronized void add(int value){
this.count += value;
}
- 静态方法
静态方法的同步是指同步在该方法所在的类对象上。
public static synchronized void add(int value){
this.count += value;
}
- 实例方法中的同步块
使用了“this”,即为调用add方法的实例本身。在同步构造器中用括号括起来的对象叫做监视器对象。
同步实例方法使用调用方法本身的实例作为监视器对象。
public void add(int value){
synchronized(this){
this.count += value;
}
}
- 静态方法中的同步块
public static synchronized void log1(String msg1, String msg2){
log.writeln(msg1);
log.writeln(msg2);
}
public static void log2(String msg1, String msg2){
synchronized(MyClass.class){
log.writeln(msg1);
log.writeln(msg2);
}
}
synchronized关键字修饰方法的时候,同步锁是this,即等效于代码块synchronized(this) {...}。
public void output(String name) {
int len = name.length();
synchronized (this) {
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
public synchronized void output(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
synchronized关键字修饰static方法的时候,同步锁是该类的字节码对象,即等效于代码块synchronized(classname.class) {...}。
public static synchronized void output(String name) {
int len = name.length();
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
public void output(String name) {
int len = name.length();
synchronized (Outputer.class) {
for (int i = 0; i < len; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
}
}
同步代码块的锁是任意对象。只要不同的线程都执行同一个同步代码块的时候,这个锁随便设。
同步函数的锁是固定的this。当需要和同步函数中的逻辑实行同步的时候,代码块中的锁必须为this。
静态同步函数的锁是该函数所属类的字节码文件对象。该对象可以用this.getClass()方法获取,也可以使用 当前类名.class 表示。
- Object的wait与notify
- 使用特殊域变量(volatile)实现线程同步
● volatile关键字为域变量的访问提供了一种免锁机制
● 使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新
● 因此每次使用该域就要重新计算,而不是使用寄存器中的值
● volatile不会提供任何原子操作,它也不能用来修饰final类型的变量 - 使用重入锁实现线程同步
注:关于Lock对象和synchronized关键字的选择:
a.最好两个都不用,使用一种java.util.concurrent包提供的机制,能够帮助用户处理所有与锁相关的代码。
b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码
c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁
public class Counter{
private int count = 0;
public int inc(){
synchronized(this){
return ++count;
}
}
}
public class Counter{
private Lock lock = new Lock();
private int count = 0;
public int inc(){
lock.lock();
int newCount = ++count;
lock.unlock();
return newCount;
}
}
- 使用局部变量实现线程同步
注:ThreadLocal与同步机制
a.ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题。
b.前者采用以"空间换时间"的方法,后者采用以"时间换空间"的方式 - 使用阻塞队列实现线程同步
● 使用LinkedBlockingQueue<E>来实现线程的同步
● LinkedBlockingQueue<E>是一个基于已连接节点的,范围任意的blocking queue。 - ReentrantLock公平策略锁---公平在等待时间最长的线程首先获得锁