在多线程中synchronized应该是我们运用的最多的,很多人会称呼它为重量级锁。java中的每一个对象都可以作为锁。具体表现为以下三种形式。
对于普通同步方法,锁是当前实例对象。
//图书
class Books {
private int id;// 图书ID
private String name; // 图书名称
private int number; // 图书数量
//存书
public void stockBooks(int count) {
number+=count;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//借书
public void taskBooks(int count) {
number-=count;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}我们先声明一个图书的对象,然后再模拟一下图书馆存书借书的场景;
// 图书馆
class bibliotheca implements Runnable {
private Books books;
public bibliotheca(Books books) {
super();
this.books = books;
}
public Books getBooks() {
return books;
}
public void setBooks(Books books) {
this.books = books;
}
@Override
public void run() {
books.stockBooks(1000); // 存入1000本书
books.taskBooks(1000);
System.out.println(Thread.currentThread().getName() + ":"
+ books.getNumber());
}
}public static void main(String[] args) {
Books books = new Books("金瓶梅", 1000); // 初始化的时候先存入1000本金瓶梅
bibliotheca bibliotheca = new bibliotheca(books); // 把图书注入到图书馆里
Thread threads[] = new Thread[10]; // 模拟10个线程
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(bibliotheca, "Thread" + i);
threads[i].start();
}
}@Override
public void run() {
synchronized (books) {
books.stockBooks(1000); // 存入1000本书
books.taskBooks(1000);
System.out.println(Thread.currentThread().getName() + ":"
+ books.getNumber());
}
}最终结果都为1000,所以这个才是我们想要的结果;
当多个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。在run方法中我们用了synchronized(books)方法给这个对象加了锁,
当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的对象来充当锁:
@Override
public void run() {
synchronized (this) {
books.stockBooks(1000); // 存入1000本书
books.taskBooks(1000);
System.out.println(Thread.currentThread().getName() + ":"
+ books.getNumber());
}
}比如上面这样,是不是很常见;或者如下面这样
private byte[] lock = new byte[0]; // 特殊的instance变量
public void method()
{
synchronized(lock) {
// todo 同步代码块
}
}
public void run() {
}
class CountThread extends Thread{
private static int count;
public CountThread() {
count = 0;
}
public synchronized static void method() {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
method();
}
}请注意我没有对run方法加同步锁,是因为,我要同步的只是method()这个具体的方法;public static void main(String[] args) {
CountThread countThread=new CountThread();
Thread threads[] = new Thread[10]; // 模拟10个线程
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(countThread, "Thread" + i);
threads[i].start();
}
}现在我们改造一下这个例子:
class CountThread extends Thread{
private static int count;
public CountThread() {
count = 0;
}
public synchronized static void method() {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void method1() {
for (int i = 0; i < 5; i ++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run() {
method();
method1();
}
}run方法里面有method()和method1();这个方法结果是加上同步锁的会保持同步,而没有加上同步锁的则会出现乱数据;
如果我们method()和method1()都没有加上同步,而想让这个两个方法同步怎么办?这就是我们要说的第三种形式;
对于同步方法块,锁是Synchonized括号里配置的对象。
public synchronized void run() {
method();
method1();
}当然你也可以这样:
public void run() {
synchronized (this) {
method();
method1();
}
}是不是很神奇!
原文:http://blog.csdn.net/liaodehong/article/details/51058252