Java的锁分为两种:
-
对象锁(又称实例锁,
synchronized
):该锁针对的是该实例对象(当前对象)。synchronized
是对类的当前实例(当前对象)进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”, 类的两个不同实例就没有这种约束了。
每个对象都有一个锁,且是唯一的。 -
类锁(又称全局锁,
static synchronized
):该锁针对的是类,无论实例出多少个对象,那么线程依然共享该锁。static synchronized
是限制多线程中该类的所有实例同时访问该类所对应的代码块。(实例.fun
实际上相当于class.fun
)
下面来进行几种情况的测试:一下都是用来测试锁的范围
1、两个静态方法都加锁
package test2;
public class Test2 {
public synchronized void add(){
System.out.println("1 :) ");
t();
}
public void add1(){
System.out.println("2 :( ");
t();
}
public void t(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2、两个非静态方法都加锁
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
// Test2.add();
t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
t.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test2 t = new Test2();
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
}
class Test2 {
public synchronized void add(){
System.out.println("1 :) "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void add1(){
System.out.println("2 :( "+System.currentTimeMillis());
}
}
结果:此时会锁住加锁的另外一个对象
3、非静态方法、静态方法都加锁
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
Test2.add();
// t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
t.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test2 t = new Test2();
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
}
class Test2 {
public synchronized static void add(){
System.out.println("1 :) "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void add1(){
System.out.println("2 :( "+System.currentTimeMillis());
}
}
结果:静态带锁的对象锁不住不带锁的非静态方法
4、静态方法加锁、非静态方法不加锁
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
Test2.add();
// t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
t.add1();
// Test2.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test2 t = new Test2();
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
}
class Test2 {
public synchronized static void add(){
System.out.println("1 :) "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void add1(){
System.out.println("2 :( "+System.currentTimeMillis());
}
}
结果:静态方法加锁,锁不住非静态方法
5、非静态方法加锁、静态方法不加锁
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
Test2.add();
// t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
t.add1();
// Test2.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test2 t = new Test2();
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
}
class Test2 {
public static void add(){
System.out.println("1 :) "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void add1(){
System.out.println("2 :( "+System.currentTimeMillis());
}
}
结果:还是锁不住!!!
6、两个静态方法,一个加锁一个不加锁
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
Test2.add();
// t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
// t.add1();
Test2.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test2 t = new Test2();
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
}
class Test2 {
public synchronized static void add(){
System.out.println("1 :) "+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void add1(){
System.out.println("2 :( "+System.currentTimeMillis());
}
}
结果:静态方法加锁,锁不住不加锁的静态方法
7、两个非静态方法,一个加锁一个不加锁
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
// Test2.add();
t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
t.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test2 t = new Test2();
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
}
class Test2 {
private int i = 0;
public synchronized void add(){
System.out.println("1 :) "+System.currentTimeMillis());
}
public void add1(){
System.out.println("2 :( "+System.currentTimeMillis());
}
}
执行结果:可以看到,加锁后的非静态方法,锁不住不加锁的静态方法
8、两个非静态方法,一个加锁,一个不加锁,调用相同的方法
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
// Test2.add();
t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
t.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
Test2 t = new Test2();
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
}
class Test2 {
public synchronized void add(){
System.out.println("1 :) "+System.currentTimeMillis());
t();
}
public void add1(){
System.out.println("2 :( "+System.currentTimeMillis());
t();
}
public void t(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果:并不会在add方法里锁住t()方法
9、两个非静态方法,一个加锁,一个不加锁,调用相同的方法对同一个变量进行操作
package test2;
public class Test1 extends Thread{
private int flag;
private Test2 t;
public Test1(int f , Test2 t2){
flag = f;
t = t2;
}
public void run(){
if(flag == 1)
try {
// Test2.add();
t.add();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(flag == 2)
try {
t.add1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException {
Test2 t = new Test2();
for(int i = 0 ; i < 1000 ; i++){
Test1 t1 = new Test1(1,t);
Test1 t2 = new Test1(2,t);
t1.start();
t2.start();
}
Thread.sleep(30);
System.out.println(t.getI());
}
}
class Test2 {
private int i = 0;
public synchronized void add(){
// System.out.println("1 :) "+System.currentTimeMillis());
t();
}
public void add1(){
// System.out.println("2 :( "+System.currentTimeMillis());
t();
}
public void t(){
try {
i++;
// Thread.sleep(5000);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
}
结果:一个方法加锁也不会保证其调用方法的操作变量的安全性
总结:不管是什么锁,都只能锁住相同类型(静态-静态,非静态-非静态)的带锁的对象。