在java中,为了避免多个线程对同一资源访问操作时候的干扰脏读,可以用synchronized来同步方法
class MyObject{
public synchronized void methodA(){
try{
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end");
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
class ThreadA extends Thread{
private MyObject object;
public ThreadA(MyObject object){
this.object = object;
}
public void run(){
object.methodA();
}
}
public class test{
public static void main(String[] args){
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
ThreadA b = new ThreadA(object);
b.setName("B");
a.start();
b.start();
}
}
运行结果:
线程B要等到线程A执行完同步方法才能去执行。
synsynchronized同步锁,锁的是它的一个对象,多个对象有多个同步锁
class HasSelfPrivateNum{
private int num = 0;
synchronized public void addI(String username){
try{
if(username.equals("a")){
num = 100;
System.out.println("a set over!");
Thread.sleep(2000);
}else{
num = 200;
System.out.println("b set over");
}
System.out.println(username + " num=" + num);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadA extends Thread{
private HasSelfPrivateNum numRef;
public ThreadA(HasSelfPrivateNum numRef){
this.numRef = numRef;
}
public void run(){
numRef.addI("a");
}
}
class ThreadB extends Thread{
private HasSelfPrivateNum numRef;
public ThreadB(HasSelfPrivateNum numRef){
this.numRef = numRef;
}
public void run(){
numRef.addI("b");
}
}
public class test2{
public static void main(String[] args){
HasSelfPrivateNum numRef1 = new HasSelfPrivateNum();
HasSelfPrivateNum numRef2 = new HasSelfPrivateNum();
ThreadA athread = new ThreadA(numRef1);
athread.start();
ThreadB bthread = new ThreadB(numRef2);
bthread.start();
}
}
执行结果:
虽然线程在HasSelfPrivateNum中使用了关键字synchronized,但打印却不是同步的,是交叉的。关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁。所以在第一个例子中,哪个线程先执行带synchronized的方法,哪个线程就持有该方法所属对象的锁,其他线程想要执行此对象synchronized的其他方法,或者synchronized块,都会被阻塞等待。如果多个线程访问的是多个对象,如此例,每个对象有自己的synchronized锁,相互独立。
synchronized方法被调用了,但非synchronized方法同时可以被调用
class MyObject{
public synchronized void methodA(){
try{
System.out.println("begin methodA threadName="
+ Thread.currentThread().getName());
Thread.sleep(5000);
System.out.println("end endTime=" + System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}
}
public void methodB(){
try{
System.out.println("begin methodB threadName="
+ Thread.currentThread().getName()
+ " beginTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("end endTime=" + System.currentTimeMillis());
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
class ThreadA extends Thread{
private MyObject object;
public ThreadA(MyObject object){
this.object = object;
}
public void run(){
object.methodA();
}
}
class ThreadB extends Thread{
private MyObject object;
public ThreadB(MyObject object){
this.object = object;
}
public void run(){
object.methodB();
}
}
public class test{
public static void main(String[] args){
MyObject object = new MyObject();
ThreadA a = new ThreadA(object);
a.setName("A");
ThreadB b = new ThreadB(object);
b.setName("B");
a.start();
b.start();
}
}
运行结果:
当持有一个synchronized锁后,可以重入其他synchronized方法,避免了死锁
class Service{
synchronized public void Service1(){
System.out.println("service1");
Service2();
}
synchronized public void Service2(){
System.out.println("service2");
Service3();
}
synchronized public void Service3(){
System.out.println("service3");
}
}
class MyThread extends Thread{
public void run(){
Service service = new Service();
service.Service1();
}
}
public class test3{
public static void main(String[] args){
MyThread t = new MyThread();
t.start();
}
}
运行结果:
结论:
1)A线程先持有object对象的锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法。
2)A线程先持有object对象的锁,B线程如果在这时调用了object对象中的synchronized类型的方法则需要等待。
最后要说明,如果在执行synchronized方法出现异常,其所持有的锁会自动释放。