pre 定义 exc 执行 zed 三种 gen 好记性不如烂笔头
好记性不如烂笔头~~
- 并发编程中
- synchronized
- 关键字的地位很重要,很多人都称它为重量级锁。利用
- synchronized
- 实现同步的基础:Java中每一个对象都可以作为锁。具体表现为以下三种形式。
(1)对于普通同步方法,锁是当前实例对象。
(2)对于静态同步方法,锁是当前类的Class对象。
(3)对于同步方法块,锁是synchronized括号里配置的对象。
一、普通同步方法
使用synchronized关键字修饰一个普通方法,锁住的是当前实例的对象。当synchronized锁住该对象后,别的线程如果也想拿到这个对象的锁,就必须等待这个线程执行完成释放锁,才能再次给对象加锁,这样才达到线程同步的目的。
实验一
- class Synch {
- public synchronized void test1() {
- System.out.println("test1开始");
- try {
- Thread.sleep(1000);
- } catch(InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("test1结束");
- }
- public synchronized void test2() {
- System.out.println("test2开始");
- try {
- Thread.sleep(1000);
- } catch(InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("test2结束");
- }
- }
- public class SyncTest extends Synch {
- public static void main(String args[]) {
- Synch s = new Synch();
- Thread t1 = new Thread(new Runnable() {
- @Override public void run() {
- // TODO Auto-generated method stub
- s.test1();
- }
- });
- Thread t2 = new Thread(new Runnable() {
- @Override public void run() {
- // TODO Auto-generated method stub
- s.test2();
- }
- });
- t1.start();
- t2.start();
- }
- }
实验结果:
分析上述代码,类Synch中有两个普通同步方法test1和test2.在主函数中实现了该类,同时定义两个thread线程,run方法中分别调用类Synch的方法。synchronized实现的普通同步方法,锁住的是当前实例对象,即Synch类对象。由于两个线程是调用的同一个对象中的同步方法,所以只有一个线程释放该对象的锁,另一个线程才能调用。
实验二
- class Sync {
- public synchronized void test(String threadname) {
- System.out.println(threadname + "开始");
- try {
- Thread.sleep(1000);
- } catch(InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println(threadname + "结束");
- }
- }
- class MyThread extends Thread {
- public int i;
- public MyThread(int i) {
- this.i = i;
- }
- Sync s = new Sync();
- public void run() {
- //Sync sync=new Sync();
- s.test("Thread" + i);
- }
- }
- public class SynTest {
- public static void main(String args[]) {
- for (int i = 0; i < 3; i++) {
- Thread thread = new MyThread(i);
- thread.start();
- }
- }
- }
实验结果:
上述代码,每个线程中都new了一个Sync类的对象,也就是产生了三个Sync对象,由于不是同一个对象,所以可以多线程同时运行synchronized方法。
二、静态同步方法
对于静态同步方法,锁是当前类的Class对象,所以,static synchronized方法也相当于全局锁,相当于锁住了代码段。只有一个线程结束后,另一个线程才能获得锁。
实验三
- class Synch {
- public static synchronized void test1() {
- System.out.println("test1开始");
- try {
- Thread.sleep(1000);
- } catch(InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("test1结束");
- }
- public static synchronized void test2() {
- System.out.println("test2开始");
- try {
- Thread.sleep(1000);
- } catch(InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("test2结束");
- }
- }
- public class SyncTest extends Synch {
- public static void main(String args[]) {
- Synch s1 = new Synch();
- Synch s2 = new Synch();
- Thread t1 = new Thread(new Runnable() {
- @Override public void run() {
- // TODO Auto-generated method stub
- s1.test1();
- }
- });
- Thread t2 = new Thread(new Runnable() {
- @Override public void run() {
- // TODO Auto-generated method stub
- s2.test2();
- }
- });
- t1.start();
- t2.start();
- }
- }
实验结果:
三、同步方法块
这部分更好理解,锁住的是synchronized括号里配置的对象。
实验四
- public class Threadtest implements Runnable {
- @Override public void run() {
- // TODO Auto-generated method stub
- synchronized(this) {
- for (int i = 0; i < 5; i++) {
- System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
- }
- }
- }
- public static void main(String[] args) {
- Threadtest t1 = new Threadtest();
- Thread ta = new Thread(t1, "A");
- Thread tb = new Thread(t1, "B");
- ta.start();
- tb.start();
- }
- }
运行结果:
上述代码,synchronized代码块括号里配置的对象是this,同一个对象,所以只有一个线程访问该代码块结束后,释放锁,另一个线程才能访问该代码块。
需要注意的是,其他线程可以访问非synchronized(this)同步代码。如下代码
实验五
- class MyThread1 {
- public void test1() {
- synchronized(this) {
- System.out.println("同步代码块-test1开始");
- try {
- Thread.sleep(1000);
- } catch(InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("同步代码块-test1结束");
- }
- }
- public void test2() {
- try {
- Thread.sleep(500);
- } catch(InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println("非同步代码块-test2");
- }
- }
- public class ThreadTest1 {
- public static void main(String args[]) {
- MyThread1 t = new MyThread1();
- Thread t1 = new Thread(new Runnable() {
- @Override public void run() {
- // TODO Auto-generated method stub
- t.test1();
- }
- });
- Thread t2 = new Thread(new Runnable() {
- @Override public void run() {
- // TODO Auto-generated method stub
- t.test2();
- }
- });
- t1.start();
- t2.start();
- }
- }
运行结果:
synchronized括号里配置的是this,只是对这一段代码进行了加锁,同一个对象,只有一个线程能访问该代码块,释放锁之后,其他线程才可以访问,但是并不影响其他线程访问非同步代码块。
同步代码块,同步方法的实现~~简单理解
对于同步代码块是使用monitorenter、monitorexit指令实现的。每个对象都有一个监视器锁(monitor),当monitor被占用时,就会处于锁定状态。
线程执行monitorenter指令尝试获取monitor的所有权。
对于同步方法,常量池中多了ACC_SYNCHRONIZED标识符,方法调用时,先检查该标识符的访问标志,如果设置了,则进程先获取monitor,获取成功后才能执行方法体,方法执行完之后再释放monitor。
整理下,要不会忘记~~参考http://www.cnblogs.com/QQParadise/articles/5059824.html
Java中synchronized关键字理解
来源: http://www.bubuko.com/infodetail-2304801.html