在多线程情况下,当多个线程操作同一个资源的时候,会出现安全问题,例如脏读(一个线程咋读取变量的时候,值已经被另一个线程改变)。
synchronized关键字:可用来同步方法或者代码块。有关synchronized,总结一下几条。
1 synchronized关键字锁的是对象,当多个对象会创建多个锁,而达不到同步的效果。
2 只有操作公共资源的时候才需要上锁,非公共资源没必要上锁。
3 synchronized关键字拥有可重入锁。
4 异常出现的时候,会自动释放锁。
5 同步不具备继承性。
6 sleep()方法不会释放锁。
7wait()方法会释放锁。
8 synchronized可同步方法,也可以同步代码块。
下面对其中几条进行验证;
方法类:
public class MyMethod {
synchronized public void methodA(String username) throws InterruptedException{
System.out.println(username);
if(username.equals("a")){
System.out.println(Thread.currentThread().getName()+" into methodA");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+" out methodA");
}
else {
System.out.println(Thread.currentThread().getName()+" into methodB");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" out methodB");
}
/*while(true){
}*/
}
//synchronized 锁代码块
public static void methodB(String lock) throws InterruptedException{
synchronized (lock) {
System.out.println(Thread.currentThread().getName()+" into lock");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" out lock");
}
}
}
主线程:synchronized同步代码块。synchronized(this)锁的是当前对象。
public class Run {
public static void main(String[] args) throws InterruptedException {
MyMethod m1=new MyMethod();
MyMethod m2=new MyMethod();
String lock="";
Thread t1 =new Thread(new Runnable() {
@Override
public void run() {
try {
m1.methodB(lock);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"t1");
Thread t2 =new Thread(new Runnable() {
@Override
public void run() {
try {
m1.methodB(lock);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"t2");
t1.start();
t2.start();
}
}
控制台:
t2 into lock t2 out lock t1 into lock t1 out lock
synchronized同步方法,修改主线程如下
public class Run {
public static void main(String[] args) throws InterruptedException {
MyMethod m1=new MyMethod();
MyMethod m2=new MyMethod();
String lock="";
Thread t1 =new Thread(new Runnable() {
@Override
public void run() {
try {
m1.methodA("a");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"t1");
Thread t2 =new Thread(new Runnable() {
@Override
public void run() {
try {
m1.methodA("b");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"t2");
t1.start();
t2.start();
}
}
控制台输出:
b t2 into methodB t2 out methodB a t1 into methodA t1 out methodA
可以发现达到同步的效果。
再次修改主线程代码如下:
public class Run {
public static void main(String[] args) throws InterruptedException {
MyMethod m1=new MyMethod();
MyMethod m2=new MyMethod();
String lock="";
Thread t1 =new Thread(new Runnable() {
@Override
public void run() {
try {
m1.methodA("a");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"t1");
Thread t2 =new Thread(new Runnable() {
@Override
public void run() {
try {
m2.methodA("b");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"t2");
t1.start();
t2.start();
}
}
控制台如下
b a t1 into methodA t2 into methodB t2 out methodB t1 out methodA
并且多次执行main方法,发现控制台打印顺序不同。此处调用的是两个对象,所以jvm会创建两个锁,互不影响,所以在锁,只能锁一个对象中的方法。证明synchronized锁的是对象。此过程中,我还测试了静态方法,当把methodA()方法改为静态的时候
两个对象一样会有同步的效果。
可重入锁概念:自己可以再次获取自己的内部锁。如有一个线程获得了某个对象的锁,此时这个对象还没有释放,当其再次想获取这个对象的锁的时候,还是可以获取的,否则会造成死锁。
每一个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。