概述
在上一节中,
我想很多购买了《Java程序员面试宝典》
问:请对比synchronized与java.util.
答案:主要相同点:
主要不同点:
恩,让我们先鄙视一下应试教育。
言归正传,我们先来看一个多线程程序。
public
class
ThreadDemo
implements
Runnable {
class Student {
private int age = 0 ;
public int getAge() {
return age;
}
public void setAge( int age) {
this .age = age;
}
}
Student student = new Student();
int count = 0 ;
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
Thread t1 = new Thread(td, " a " );
Thread t2 = new Thread(td, " b " );
Thread t3 = new Thread(td, " c " );
t1.start();
t2.start();
t3.start();
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running! " );
synchronized ( this ) { // (1)使用同一个ThreadDemo对象作为同步锁
System.out.println(currentThreadName + " got lock1@Step1! " );
try {
count ++ ;
Thread.sleep( 5000 );
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count: " + count);
}
}
System.out.println(currentThreadName + " release lock1@Step1! " );
synchronized ( this ) { // (2)使用同一个ThreadDemo对象作为同步锁
System.out.println(currentThreadName + " got lock2@Step2! " );
try {
Random random = new Random();
int age = random.nextInt( 100 );
System.out.println( " thread " + currentThreadName + " set age to: " + age);
this .student.setAge(age);
System.out.println( " thread " + currentThreadName + " first read age is: " + this .student.getAge());
Thread.sleep( 5000 );
} catch (Exception ex) {
ex.printStackTrace();
} finally {
System.out.println( " thread " + currentThreadName + " second read age is: " + this .student.getAge());
}
}
System.out.println(currentThreadName + " release lock2@Step2! " );
}
}
转载注明出处:http://x-spirit.javaeye.com/、http://www.blogjava.net/zhangwei217245/
class Student {
private int age = 0 ;
public int getAge() {
return age;
}
public void setAge( int age) {
this .age = age;
}
}
Student student = new Student();
int count = 0 ;
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
Thread t1 = new Thread(td, " a " );
Thread t2 = new Thread(td, " b " );
Thread t3 = new Thread(td, " c " );
t1.start();
t2.start();
t3.start();
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running! " );
synchronized ( this ) { // (1)使用同一个ThreadDemo对象作为同步锁
System.out.println(currentThreadName + " got lock1@Step1! " );
try {
count ++ ;
Thread.sleep( 5000 );
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count: " + count);
}
}
System.out.println(currentThreadName + " release lock1@Step1! " );
synchronized ( this ) { // (2)使用同一个ThreadDemo对象作为同步锁
System.out.println(currentThreadName + " got lock2@Step2! " );
try {
Random random = new Random();
int age = random.nextInt( 100 );
System.out.println( " thread " + currentThreadName + " set age to: " + age);
this .student.setAge(age);
System.out.println( " thread " + currentThreadName + " first read age is: " + this .student.getAge());
Thread.sleep( 5000 );
} catch (Exception ex) {
ex.printStackTrace();
} finally {
System.out.println( " thread " + currentThreadName + " second read age is: " + this .student.getAge());
}
}
System.out.println(currentThreadName + " release lock2@Step2! " );
}
}
运行结果:
a is running!
a got lock1@Step1!
b is running!
c is running!
a first Reading count: 1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to: 76
thread a first read age is: 76
thread a second read age is: 76
a release lock2@Step2!
c got lock1@Step1!
c first Reading count: 2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to: 35
thread c first read age is: 35
thread c second read age is: 35
c release lock2@Step2!
b got lock1@Step1!
b first Reading count: 3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to: 91
thread b first read age is: 91
thread b second read age is: 91
b release lock2@Step2!
成功生成(总时间: 30 秒)
a got lock1@Step1!
b is running!
c is running!
a first Reading count: 1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to: 76
thread a first read age is: 76
thread a second read age is: 76
a release lock2@Step2!
c got lock1@Step1!
c first Reading count: 2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to: 35
thread c first read age is: 35
thread c second read age is: 35
c release lock2@Step2!
b got lock1@Step1!
b first Reading count: 3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to: 91
thread b first read age is: 91
thread b second read age is: 91
b release lock2@Step2!
成功生成(总时间: 30 秒)
显然,在这个程序中,
转载注明出处:http://x-spirit.javaeye.com/、http://www.blogjava.net/zhangwei217245/
我想一定有人会说:
那么好。我们把第二个同步块中的对象锁改为student(
a is running!
a got lock1@Step1!
b is running!
c is running!
a first Reading count: 1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to: 73
thread a first read age is: 73
c got lock1@Step1!
thread a second read age is: 73
a release lock2@Step2!
c first Reading count: 2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to: 15
thread c first read age is: 15
b got lock1@Step1!
thread c second read age is: 15
c release lock2@Step2!
b first Reading count: 3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to: 19
thread b first read age is: 19
thread b second read age is: 19
b release lock2@Step2!
成功生成(总时间: 21 秒)
a got lock1@Step1!
b is running!
c is running!
a first Reading count: 1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to: 73
thread a first read age is: 73
c got lock1@Step1!
thread a second read age is: 73
a release lock2@Step2!
c first Reading count: 2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to: 15
thread c first read age is: 15
b got lock1@Step1!
thread c second read age is: 15
c release lock2@Step2!
b first Reading count: 3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to: 19
thread b first read age is: 19
thread b second read age is: 19
b release lock2@Step2!
成功生成(总时间: 21 秒)
从修改后的运行结果来看,显然,由于同步块的对象锁不同了,
转载注明出处:http://x-spirit.javaeye.com/、http://www.blogjava.net/zhangwei217245/
可见,使用不同的对象锁,在不同的同步块中完成任务,
很多人看到这不禁要问:这和新的Lock框架有什么关系?
别着急。我们这就来看一看。
synchronized块的确不错,
1.它无法中断一个正在等候获得锁的线程,
2.
转载注明出处:http://x-spirit.javaeye.com/、http://www.blogjava.net/zhangwei217245/
java.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象,它允许把锁定的实现作为 Java类,而不是作为语言的特性来实现。这就为 Lock 的多种实现留下了空间,各种实现可能有不同的调度算法、
JDK官方文档中提到:
ReentrantLock是“一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,
ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。
简单来说,
转载注明出处:http://x-spirit.javaeye.com/、http://www.blogjava.net/zhangwei217245/
ReentrantLock 类(重入锁)实现了 Lock ,它拥有与 synchronized相同的并发性和内存语义,但是添加了类似锁投票、
我们把上面的例程改造一下:
public
class
ThreadDemo
implements
Runnable {
class Student {
private int age = 0 ;
public int getAge() {
return age;
}
public void setAge( int age) {
this .age = age;
}
}
Student student = new Student();
int count = 0 ;
ReentrantLock lock1 = new ReentrantLock(false);
ReentrantLock lock2 = new ReentrantLock(false );
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
for ( int i = 1 ; i <= 3 ; i ++ ) {
Thread t = new Thread(td, i + "" );
t.start();
}
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running! " );
lock1.lock(); // 使用重入锁
System.out.println(currentThreadName + " got lock1@Step1! " );
try {
count ++ ;
Thread.sleep( 5000 );
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count: " + count);
lock1.unlock();
System.out.println(currentThreadName + " release lock1@Step1! " );
}
lock2.lock(); // 使用另外一个不同的重入锁
System.out.println(currentThreadName + " got lock2@Step2! " );
try {
Random random = new Random();
int age = random.nextInt( 100 );
System.out.println( " thread " + currentThreadName + " set age to: " + age);
this .student.setAge(age);
System.out.println( " thread " + currentThreadName + " first read age is: " + this .student.getAge());
Thread.sleep( 5000 );
} catch (Exception ex) {
ex.printStackTrace();
} finally {
System.out.println( " thread " + currentThreadName + " second read age is: " + this .student.getAge());
lock2.unlock();
System.out.println(currentThreadName + " release lock2@Step2! " );
}
}
}
class Student {
private int age = 0 ;
public int getAge() {
return age;
}
public void setAge( int age) {
this .age = age;
}
}
Student student = new Student();
int count = 0 ;
ReentrantLock lock1 = new ReentrantLock(false);
ReentrantLock lock2 = new ReentrantLock(false );
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
for ( int i = 1 ; i <= 3 ; i ++ ) {
Thread t = new Thread(td, i + "" );
t.start();
}
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running! " );
lock1.lock(); // 使用重入锁
System.out.println(currentThreadName + " got lock1@Step1! " );
try {
count ++ ;
Thread.sleep( 5000 );
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count: " + count);
lock1.unlock();
System.out.println(currentThreadName + " release lock1@Step1! " );
}
lock2.lock(); // 使用另外一个不同的重入锁
System.out.println(currentThreadName + " got lock2@Step2! " );
try {
Random random = new Random();
int age = random.nextInt( 100 );
System.out.println( " thread " + currentThreadName + " set age to: " + age);
this .student.setAge(age);
System.out.println( " thread " + currentThreadName + " first read age is: " + this .student.getAge());
Thread.sleep( 5000 );
} catch (Exception ex) {
ex.printStackTrace();
} finally {
System.out.println( " thread " + currentThreadName + " second read age is: " + this .student.getAge());
lock2.unlock();
System.out.println(currentThreadName + " release lock2@Step2! " );
}
}
}
从上面这个程序我们看到:
对象锁的获得和释放是由手工编码完成的,
转载注明出处:http://x-spirit.javaeye.com/、http://www.blogjava.net/zhangwei217245/
这说明两点问题:
1. 新的ReentrantLock的确实现了和同步块相同的语义功
2. 使用新的ReentrantLock,
3.使用新的ReentrantLock,
转载注明出处:http://x-spirit.javaeye.com/、http://www.blogjava.net/zhangwei217245/
细心的读者又发现了:
在我们的例程中,创建ReentrantLock实例的时候,
请看本节的续 ———— Fair or Unfair? It is aquestion...
Lock是 java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的更广泛的锁定操作,它能以更优雅的方式处理线程同步问题,我们拿Java线程(二)中的一个例子简单的实现一下和sychronized一样的效果,代码如下:
- public class LockTest {
- public static void main(String[] args) {
- final Outputter1 output = new Outputter1();
- new Thread() {
- public void run() {
- output.output("zhangsan");
- };
- }.start();
- new Thread() {
- public void run() {
- output.output("lisi");
- };
- }.start();
- }
- }
- class Outputter1 {
- private Lock lock = new ReentrantLock();// 锁对象
- public void output(String name) {
- // TODO 线程输出方法
- lock.lock();// 得到锁
- try {
- for(int i = 0; i < name.length(); i++) {
- System.out.print(name.charAt(i));
- }
- } finally {
- lock.unlock();// 释放锁
- }
- }
- }
如果说这就是Lock,那么它不能成为同步问题更完美的处理方式,下面要介绍的是读写锁(ReadWriteLock),我们会有一种需求,在对数据进行读写的时候,为了保证数据的一致性和完整性,需要读和写是互斥的,写和写是互斥的,但是读和读是不需要互斥的,这样读和读不互斥性能更高些,来看一下不考虑互斥情况的代码原型:
- public class ReadWriteLockTest {
- public static void main(String[] args) {
- final Data data = new Data();
- for (int i = 0; i < 3; i++) {
- new Thread(new Runnable() {
- public void run() {
- for (int j = 0; j < 5; j++) {
- data.set(new Random().nextInt(30));
- }
- }
- }).start();
- }
- for (int i = 0; i < 3; i++) {
- new Thread(new Runnable() {
- public void run() {
- for (int j = 0; j < 5; j++) {
- data.get();
- }
- }
- }).start();
- }
- }
- }
- class Data {
- private int data;// 共享数据
- public void set(int data) {
- System.out.println(Thread.currentThread().getName() + "准备写入数据");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- this.data = data;
- System.out.println(Thread.currentThread().getName() + "写入" + this.data);
- }
- public void get() {
- System.out.println(Thread.currentThread().getName() + "准备读取数据");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "读取" + this.data);
- }
- }
- Thread-1准备写入数据
- Thread-3准备读取数据
- Thread-2准备写入数据
- Thread-0准备写入数据
- Thread-4准备读取数据
- Thread-5准备读取数据
- Thread-2写入12
- Thread-4读取12
- Thread-5读取5
- Thread-1写入12
- public synchronized void set(int data) {...}
- public synchronized void get() {...}
- Thread-0准备写入数据
- Thread-0写入9
- Thread-5准备读取数据
- Thread-5读取9
- Thread-5准备读取数据
- Thread-5读取9
- Thread-5准备读取数据
- Thread-5读取9
- Thread-5准备读取数据
- Thread-5读取9
- class Data {
- private int data;// 共享数据
- private ReadWriteLock rwl = new ReentrantReadWriteLock();
- public void set(int data) {
- rwl.writeLock().lock();// 取到写锁
- try {
- System.out.println(Thread.currentThread().getName() + "准备写入数据");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- this.data = data;
- System.out.println(Thread.currentThread().getName() + "写入" + this.data);
- } finally {
- rwl.writeLock().unlock();// 释放写锁
- }
- }
- public void get() {
- rwl.readLock().lock();// 取到读锁
- try {
- System.out.println(Thread.currentThread().getName() + "准备读取数据");
- try {
- Thread.sleep(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + "读取" + this.data);
- } finally {
- rwl.readLock().unlock();// 释放读锁
- }
- }
- }
部分输出结果:
- Thread-4准备读取数据
- Thread-3准备读取数据
- Thread-5准备读取数据
- Thread-5读取18
- Thread-4读取18
- Thread-3读取18
- Thread-2准备写入数据
- Thread-2写入6
- Thread-2准备写入数据
- Thread-2写入10
- Thread-1准备写入数据
- Thread-1写入22
- Thread-5准备读取数据
从结果可以看出实现了我们的需求,这只是锁的基本用法,锁的机制还需要继续深入学习。
本文来自: 高爽|Coder,原文地址: http://blog.csdn.net/ghsau/article/details/7461369,转载请注明。最后
以上就是听话秀发为你收集整理的Java多线程中 synchronized和Lock的区别的全部内容,希望文章能够帮你解决Java多线程中 synchronized和Lock的区别所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复