参考资料
1 java synchronized详解
http://www.cnb
logs.com/GnagWang/archive/2011/02/27/1966606.html
java
关键字: synchronized,它包括两种用法:synchronized 方法和 synchronized 块.
它用来修饰一个方法或者一个代码块时,保证在同一时刻
最多只有一个
线程执行该段代码,
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
synchronized 方法的缺陷:若将一个大的方法声明为synchronized 将会大大影响效率,推荐使用,
synchronized 块
synchronized 块:通过 synchronized关键字来声明synchronized 块。语法如下:
synchronized(syncObject) {
//允许访问控制的代码
}
synchronized 块是这样一个代码块,其中的代码必须获得对象 syncObject的锁方能执行,由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高.
示例如下:请参见
注释
package net.liuzd.thread.synchronizeds;
public class ThreadSynchronized {
public static void main(String[] args) {
new ThreadSynchronized().init();
}
private void init() {
final OutPut op = new OutPut();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("abcdefghi");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("123456789");
}
}
}).start();
}
class OutPut {
private String test = "";
public void output(String name) {
//产生问题所在:A线程与B线程用的不是同一个字符串对象,因为name这个字符串会发生变化,所以这样设置还是不行的,始终使用的是同一个对象才能起到互斥的效果
/*synchronized(name){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}*/
//所以作如下修改,声明一个局部变量作互斥效果
synchronized(test){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
//通过这样的设置就解决这个问题了
//或者是以下这种方式
/*synchronized(this){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}*/
}
}
}
package net.liuzd.thread.synchronizeds;
public class ThreadSynchronized2 {
/**
* @param args
*/
public static void main(String[] args) {
new ThreadSynchronized2().init();
}
private void init() {
final OutPut op = new OutPut();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("abcdefghi");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//op.output("123456789");
//如果我们这里重新实例化一个对象来调用的话,那么将会产生不同步的状况了
new OutPut().output("123456789");
}
}
}).start();
}
class OutPut {
public void output(String name) {
/*synchronized(this){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
*/
//在内存中类的二进制代码始终保持一致的
synchronized(OutPut.class){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
}
}
}
package net.liuzd.thread.synchronizeds;
public class ThreadSynchronized3 {
public static void main(String[] args) {
new ThreadSynchronized3().init();
}
private void init() {
final OutPut op = new OutPut();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("abcdefghi");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output2("123456789");
}
}
}).start();
}
class OutPut {
public void output(String name) {
//在内存中类的二进制代码始终保持一致的
//用OutPut.class不能进行互斥
synchronized(this){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
}
//方法上用的同步指的是this对象,那么和第一个方法用的是同一把锁
public synchronized void output2(String name) {
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
}
}
package net.liuzd.thread.synchronizeds;
public class ThreadSynchronized4 {
public static void main(String[] args) {
new ThreadSynchronized4().init();
}
private void init() {
final OutPut op = new OutPut();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("abcdefghi");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
new OutPut().output2("123456789");
//如果我们这里重新实例化一个对象来调用的话,那么将会产生不同步的状况了
//因为重新实例化一个对象在内存的字节码是不一样,这样线程也不会进行互斥了
//解决方式是声明类为静态的
}
}
}).start();
}
static class OutPut {
public void output(String name) {
//用OutPut.class,this不能进行互斥
synchronized(OutPut.class){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
}
public static synchronized void output2(String name) {
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
}
}
package net.liuzd.thread.synchronizeds;
public class ThreadSynchronized5 {
public static void main(String[] args) {
new ThreadSynchronized5().init();
}
private void init() {
final OutPut op = new OutPut();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output("abcdefghi");
//op.output2("abcdefghi");
//用output2与output3不能进行互斥效果
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
op.output3("123456789");
}
}
}).start();
}
static class OutPut {
public void output(String name) {
//用OutPut.class与output3可以进行互斥效果
//用this与output2可以进行互斥效果
synchronized(OutPut.class){
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
}
public synchronized void output2(String name) {
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
public static synchronized void output3(String name) {
for (char c : name.toCharArray()) {
System.out.print(c);
}
System.out.println();
}
}
}
synchronized总结如下:
一 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
二.每个对象只有一个锁(lock)与之相关联。
三.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制.