使用synchronizd声明的方法在某些情况下是由弊端的,比如A线程调用同步的方法执行一个很长时间的任务,那么B线程就必须等待比较长的时间才能执行,这样的情况下可以使用synchronized代码块去优化代码执行时间,也就是通常所说的减小锁的粒度。
synchronized可以使用任意的Object进行加锁,用法比较灵活:
package edu.sdut.thread01;
/** * 使用synchronized代码块加锁,比较灵活 * @author Vision_TXG * */ public class MyThread07 { public void method1() { synchronized(this) { //对象锁 try { System.out.println("do method1.."); Thread.sleep(2000); }catch(Exception e) { e.printStackTrace(); } } } public void method2() {//类锁 synchronized (MyThread07.class) { try { System.out.println("do method2.."); Thread.sleep(2000); }catch(Exception e) { e.printStackTrace(); } } } private Object lock = new Object(); public void method3() {//任何对象锁 synchronized (lock) { try { System.out.println("do method3.."); Thread.sleep(2000); }catch(Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { final MyThread07 m = new MyThread07(); Thread t1 = new Thread(new Runnable() {
@Override public void run() { // TODO Auto-generated method stub m.method1(); } }); Thread t2 = new Thread(new Runnable() {
@Override public void run() { // TODO Auto-generated method stub m.method2(); } }); Thread t3 = new Thread(new Runnable() {
@Override public void run() { // TODO Auto-generated method stub m.method3(); } }); t1.start(); t2.start(); t3.start(); } }
|
另外特别注意一个问题,就是不要使用String的常量进行加锁,会出现死循环问题:
package edu.sdut.thread01;
/** * synchronized代码块对字符串的锁,注意String常量的缓存功能 * @author Vision_TXG * */ public class MyThread08 { /** * 使用字符串常量的时候,因为只有一个引用,所以对常量进行加锁的时候,一个线程访问后,另一个线程无法访问 * 相当于加一个类锁 * * 而使用new String("")的话表示每个线程在执行的时候,加锁的时候是针对的不同的对象 */ public void method() { //new String("字符串常量") synchronized(/*MyThread08.class*/new String("字符串常量")/*"字符串常量"*/) { try { while(true) { System.out.println("当前线程 :" + Thread.currentThread().getName()+" 开始"); Thread.sleep(1000); System.out.println("当前线程 :" + Thread.currentThread().getName()+" 结束 "); } }catch(Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { final MyThread08 m = new MyThread08(); Thread t1 = new Thread(new Runnable() {
@Override public void run() { // TODO Auto-generated method stub m.method(); } },"t1"); Thread t2 = new Thread(new Runnable() {
@Override public void run() { // TODO Auto-generated method stub m.method(); } },"t2"); t1.start(); t2.start(); } }
|
镜对象的改变问题,当使用一个对象进行加锁的时候,要注意对象本身发生改变的时候,那么持有的锁就不同。如果对象本身不发生改变,那么依然是同步的,即使是对象的属性发生了改变。