java中可以利用锁锁住一些代码块,让同一时间只有一个线程访问共用一把锁的代码块。锁分为类锁和对象锁,类锁是静态的,跟随类,而方法锁是属于实例的。synchronized关键字表示告诉监视器此段代码加锁,其他线程不允许访问,类或者对象都只拥有一把锁,当某个线程正在运行某段加锁代码时,其他任何线程都不能运行类或对象的任何其他加锁代码。
synchronized可以加在方法前:
[static] synchronized method( ) { }
或者这样加在代码块前:
synchronized(object|class){ }
当其修饰静态方法和传入类的代码块时,此锁是类锁,类锁属于类,与任何实例无关:
static synchronized method( ) { } synchronized(class){ }
当其修饰实例方法和传入对象的代码块时,此锁是对象锁,只影响这个对象:
synchronized method( ) { } synchronized(object){ }
测试对象锁:
public class MethodSyncTest { public int dataint = 0; public String datastr; public boolean databool; public synchronized void setInt(){ for (int x = 0; x < 10; x++) { dataint = x+1; System.out.println("将整数设置为: "+dataint); } } public synchronized void setString() { for (int x = 0; x < 10; x++) { datastr = "字符串" + (x+1); System.out.println("将字符串设置为: "+datastr); } } public synchronized void setBoolean() { for (int x = 0; x < 10; x++) { if (databool) { databool = false; } else { databool = true; } System.out.println("将布尔值设置为: "+databool); } } }
MethodSyncTest test = new MethodSyncTest(); Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("当前线程: "+Thread.currentThread().getName()); test.setInt(); } }, "线程1"); Thread t2 =new Thread(new Runnable() { @Override public void run() { System.out.println("当前线程: "+Thread.currentThread().getName()); test.setString(); } }, "线程2"); Thread t3 =new Thread(new Runnable() { @Override public void run() { System.out.println("当前线程: "+Thread.currentThread().getName()); test.setBoolean(); } }, "线程3"); t1.start(); t2.start(); t3.start();
运行结果:
当前线程: 线程2 当前线程: 线程1 当前线程: 线程3 将字符串设置为: 字符串1 将字符串设置为: 字符串2 将字符串设置为: 字符串3 将字符串设置为: 字符串4 将字符串设置为: 字符串5 将字符串设置为: 字符串6 将字符串设置为: 字符串7 将字符串设置为: 字符串8 将字符串设置为: 字符串9 将字符串设置为: 字符串10 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将整数设置为: 1 将整数设置为: 2 将整数设置为: 3 将整数设置为: 4 将整数设置为: 5 将整数设置为: 6 将整数设置为: 7 将整数设置为: 8 将整数设置为: 9 将整数设置为: 10
测试类锁:
public class MethodSyncTest { public static int dataint = 0; public static String datastr; public static boolean databool; public static synchronized void setInt(){ for (int x = 0; x < 10; x++) { dataint = x+1; System.out.println("将整数设置为: "+dataint); } } public static synchronized void setString() { for (int x = 0; x < 10; x++) { datastr = "字符串" + (x+1); System.out.println("将字符串设置为: "+datastr); } } public static synchronized void setBoolean() { for (int x = 0; x < 10; x++) { if (databool) { databool = false; } else { databool = true; } System.out.println("将布尔值设置为: "+databool); } } }
Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("当前线程: "+Thread.currentThread().getName()); MethodSyncTest.setInt(); } }, "线程1"); Thread t2 =new Thread(new Runnable() { @Override public void run() { System.out.println("当前线程: "+Thread.currentThread().getName()); MethodSyncTest.setString(); } }, "线程2"); Thread t3 =new Thread(new Runnable() { @Override public void run() { System.out.println("当前线程: "+Thread.currentThread().getName()); MethodSyncTest.setBoolean(); } }, "线程3"); t1.start(); t2.start(); t3.start();
运行结果:
当前线程: 线程3 当前线程: 线程2 当前线程: 线程1 将整数设置为: 1 将整数设置为: 2 将整数设置为: 3 将整数设置为: 4 将整数设置为: 5 将整数设置为: 6 将整数设置为: 7 将整数设置为: 8 将整数设置为: 9 将整数设置为: 10 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将布尔值设置为: true 将布尔值设置为: false 将字符串设置为: 字符串1 将字符串设置为: 字符串2 将字符串设置为: 字符串3 将字符串设置为: 字符串4 将字符串设置为: 字符串5 将字符串设置为: 字符串6 将字符串设置为: 字符串7 将字符串设置为: 字符串8 将字符串设置为: 字符串9 将字符串设置为: 字符串10
可以看到所有的加锁方法,其实都是共用同一把锁。