Synchronized的使用方法

一、同步代码块

用synchronized把要出现线程安全问题的代码包起来,每次只能有一个线程执行

public class TestWindow1 {
	public static void main(String[] args) {
		Window1 w = new Window1();

		Thread t1 = new Thread(w);
		Thread t2 = new Thread(w);
		Thread t3 = new Thread(w);

		t1.setName("窗口1");
		t2.setName("窗口2");
		t3.setName("窗口3");

		t1.start();
		t2.start();
		t3.start();
	}
}
class Window1 implements Runnable {
	int ticket = 100; // 共享数据
	public void run() {
		while (true) {
			synchronized (this) {
				if (ticket > 0) {
					try {
						Thread.currentThread().sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()
							+ "售票,票号为:" + ticket--);
				} else {
				    break;
                }
			}
		}
	}
}

上面代码中synchronized使用的锁为当前对象,即创建的Window1的实例,当然也可以使用其他的类实例

public class TestWindow2 {
	public static void main(String[] args) {
		Window2 w1 = new Window2();
		Window2 w2 = new Window2();
		Window2 w3 = new Window2();

		w1.setName("窗口1");
		w2.setName("窗口2");
		w3.setName("窗口3");

		w1.start();
		w2.start();
		w3.start();
	}
}
class Window2 extends Thread {
	static int ticket = 100;
	static Object obj = new Object();

	public void run() {
		while (true) {
			// synchronized (this) {//在本问题中,this表示:w1,w2,w3
			synchronized (obj) {
				if (ticket > 0) {
					try {
						Thread.currentThread().sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()
							+ "售票,票号为:" + ticket--);
				} else {
                    break;
                }
			}
		}
	}
}

上面的代码中,创建多线程的方式与第一种不同,这里是继承Thread 类的方式,因此在创建三个线程的时候,创建了三个Window2的实例对象,所以再使用this作为锁的时候,this为三个对象本身,所以三个线程使用的并不是同一把锁,所以并不能达到线程同步的目的,这里要使用其他的类对象来充当锁

二、同步方法
public class SynchronizedTest1 {
    public synchronized void methodA() {
        try {
            for (int i = 0; i < 3; i++) {
                System.out.println("methodA-" + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void methodB() {
        synchronized (this) {
            try {
                for (int i = 0; i < 3; i++) {
                    System.out.println("methodB-" + i);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void methodC() {
        Object obj = new Object();
        synchronized (obj) {
            try {
                for (int i = 0; i < 3; i++) {
                    System.out.println("methodC-" + i);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SynchronizedTest1 test1 = new SynchronizedTest1();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test1.methodA();
            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test1.methodB();
            }
        });
        thread2.start();

        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                test1.methodC();
            }
        });
        thread3.start();

    }
}
执行结果:
methodA-0
methodC-0
methodA-1
methodC-1
methodA-2
methodC-2
methodB-0
methodB-1
methodB-2

在非静态方法上加synchronized修饰,同样能达到同步的目的,thread1 和 thread2 两个线程同时执行同一个对象被synchronized修饰的方法时,只能有一个线程执行,另一个线程处于等待,此时锁为this,即当前对象。基于上面的分析,下面的使用方式将不会达到同步的效果

class Window2 extends Thread {
	static int ticket = 100;//共享数据
	
	public void run() {
		while (true) {
			show();
		}
	}
	public synchronized void show() {//this锁,这里创建了三个window的对象,执行的时候三个线程三把锁,所以同步方法不用在继承的方式中
		if (ticket > 0) {
			try {
				Thread.currentThread().sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "售票,票号为:"
					+ ticket--);
		}
	}
}

public class TestWindow2 {
	public static void main(String[] args) {
		Window2 w1 = new Window2();
		Window2 w2 = new Window2();
		Window2 w3 = new Window2();

		w1.setName("窗口1");
		w2.setName("窗口2");
		w3.setName("窗口3");

		w1.start();
		w2.start();
		w3.start();
	}
}
三、静态同步方法
public class SynchronizedTest2 {
    public synchronized static void methodA() {
        try {
            for (int i = 0; i < 3; i++) {
                System.out.println("methodA-" + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void methodB() {
        synchronized (SynchronizedTest2.class) {
            try {
                for (int i = 0; i < 3; i++) {
                    System.out.println("methodB-" + i);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SynchronizedTest2 test2 = new SynchronizedTest2();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test2.methodA();
            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test2.methodB();
            }
        });
        thread2.start();
    }
}
执行结果:
methodA-0
methodA-1
methodA-2
methodB-0
methodB-1
methodB-2

使用synchronized 修饰静态方法时的锁为当前类对象(注意不是当前类实例对象)即:
Class<SynchronizedTest2> aClass = SynchronizedTest2.class;

public class SynchronizedTest3 {
    public synchronized void methodA() {
        try {
            for (int i = 0; i < 3; i++) {
                System.out.println("methodA-" + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized static void methodB() {
        try {
            for (int i = 0; i < 3; i++) {
                System.out.println("methodB-" + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SynchronizedTest3 test3 = new SynchronizedTest3();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test3.methodA();
            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test3.methodB();
            }
        });
        thread2.start();
    }
}
执行结果:
methodA-0
methodB-0
methodA-1
methodB-1
methodA-2
methodB-2

上面代码中,一个方法使用的是实例对象锁,一个方法使用的是类对象锁,两个线程使用两个把锁,可以同时执行。而当两个线程执行同一个类的两个实例对象的非静态方法时,也是同时执行的,原因是锁为两个实例对象,当执行的是静态方法时,两个线程则不能同时执行,因为锁还是同一把锁(类对象)

synchronized可重入锁?
public class Synchronized1 {

    public  synchronized void method1(){
        System.out.println("method1方法执行");
        method2();
    }

    public  synchronized void method2(){
        System.out.println("method2方法执行");
        method3();
    }

    public  synchronized void method3(){
        System.out.println("method3方法执行");
    }

    public static void main(String[] args) {
        Synchronized1 sd1 = new Synchronized1();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                sd1.method1();
            }
        });
        t1.start();
    }
}
执行结果:
method1方法执行
method2方法执行
method3方法执行

上面代码可以看出synchronized 是可重入的,关于重入锁后面单独总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值