多线程同时访问一个资源,可以会产生不可预料的结果,所以为这个资源加锁, 访问资源的第一个线程为其加锁后,其他线程便不能在使用那个资源,直到锁被解除。
举个例子:
存款 1000 元,能取出 800 的时候我就取 800,当我同时用两个线程调用这个取钱操作时,有时可以取出 1600 元
- static class HelloRunable implements Runnable{
- private int money = 1000;
- //取出800元
- int getMoney() {
- System.out.println("开始" + money);
- if(money > 800) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- money -= 800;
- System.out.println("我取了800元" + money);
- }
- System.out.println("结束" + money);
- return money;
- }
- @Override
- public void run() {
- money = getMoney();
- }
- }
- public static void main(String[] args) {
- HelloRunable helloRunable = new HelloRunable();
- Thread t = new Thread(helloRunable);
- Thread t1 = new Thread(helloRunable);
- t.start();
- t1.start();
- }
synchronized:
所以我们引入了同步机制,在取钱方法前面加入了 synchronized 关键字,该方法称为同步方法,输出结果为
java 中每个对象都有一个锁,或者叫做监视器 (monitor), 当一个线程访问某个对象的 synchronized 方法时,将该对象上锁,其他任何线程都无法再去访问该对象的 synchronized 方法,直到之前的那个线程执行完方法之后,才会将对象锁释放,其他线程才可以在用该对象的 synchronized 方法。 注:这是给对象上锁,如果是不同的对象则该对象之间没有限制关系。
如果一个对象有多个 synchronized 方法,某一时刻某个线程已经进入到了 synchronized 方法,那么在该方法没有执行完前,其他线程是无法访问该对象的任何 synchronized 方法的。
例如:
- public static void main(String[] args)
- {
- Example example = new Example();
- Thread t1 = new Thread1(example);
- Thread t2 = new Thread2(example);
- t1.start();
- t2.start();
- }
- static class Example
- {
- public synchronized void execute()
- {
- for (int i = 0; i < 20; ++i)
- {
- try
- {
- Thread.sleep((long) Math.random() * 1000);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- System.out.println("Hello: " + i);
- }
- }
- public void execute2()
- {
- for (int i = 0; i < 20; ++i)
- {
- try
- {
- Thread.sleep((long) Math.random() * 1000);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- System.out.println("World: " + i);
- }
- }
- }
- static class Thread1 extends Thread
- {
- private Example example;
- public Thread1(Example example)
- {
- this.example = example;
- }
- @Override
- public void run()
- {
- example.execute();
- }
- }
- static class Thread2 extends Thread
- {
- private Example example;
- public Thread2(Example example)
- {
- this.example = example;
- }
- @Override
- public void run()
- {
- example.execute2();
- }
- }
当加上 synchronized 后, 当同步方法未执行完时另一个同步方法不会执行
静态的同步方法
当一个 synchronized 关键字修饰的方法同时被 static 修饰,非静态的同步方法会将对象上锁,但是静态方法不属于对象,而是属于类,他会将这个方法所在的类的 Class 对象上锁。
- public static void main(String[] args)
- {
- Example example = new Example();
- Thread t1 = new Thread1(example);
- example = new Example();
- Thread t2 = new Thread2(example);
- t1.start();
- t2.start();
- }
- static class Example
- {
- public static synchronized void execute()
- {
- for (int i = 0; i < 20; ++i)
- {
- try
- {
- Thread.sleep((long) Math.random() * 1000);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- System.out.println("Hello: " + i);
- }
- }
- public static synchronized void execute2()
- {
- for (int i = 0; i < 20; ++i)
- {
- try
- {
- Thread.sleep((long) Math.random() * 1000);
- }
- catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- System.out.println("World: " + i);
- }
- }
- }
- static class Thread1 extends Thread
- {
- private Example example;
- public Thread1(Example example)
- {
- this.example = example;
- }
- @Override
- public void run()
- {
- example.execute();
- }
- }
- static class Thread2 extends Thread
- {
- private Example example;
- public Thread2(Example example)
- {
- this.example = example;
- }
- @Override
- public void run()
- {
- example.execute2();
- }
- }
不加静态方法方法:
当某个 synchronized 方法是 static 的,那么当线程访问该方法时,他锁的并不是 synchronized 方法所在的对象,而是 synchronized 方法所在类的对应的 class 对象(java 中,一个类无论有多少对象,这些对象会对应唯一的 class 对象,因此当线程分别访问一个类的两个对象的的两个 static synchronized 方法时,他们的执行顺序也是有顺序的,也就是说一个线程先去执行,执行完释放锁,另一个线程再去执行)
synchronized 代码块
synchronized(object) {
}
表示的是在执行过程中会将 object 对象上锁(这个对象可以使任意类的对象,也可以使用 this),可以自行规定上锁对象
- public class test {
- public static void main(String[] args) {
- Example example = new Example();
- Thread t1 = new Thread1(example);
- Thread t2 = new Thread2(example);
- t1.start();
- t2.start();
- }
- }
- class Example {
- private Object object = new Object();
- public void execute() {
- System.out.println("我开始了");
- synchronized (object) {
- for (int i = 0; i < 20; ++i) {
- try {
- Thread.sleep((long) Math.random() * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("Hello: " + i);
- }
- }
- }
- public void execute2() {
- System.out.println("我也开始了");
- synchronized (object) {
- for (int i = 0; i < 20; ++i) {
- try {
- Thread.sleep((long) Math.random() * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("World: " + i);
- }
- }
- }
- }
- class Thread1 extends Thread {
- private Example example;
- public Thread1(Example example) {
- this.example = example;
- }
- @Override
- public void run() {
- example.execute();
- }
- }
- class Thread2 extends Thread {
- private Example example;
- public Thread2(Example example) {
- this.example = example;
- }
- @Override
- public void run() {
- example.execute2();
- }
- }
可以看到除了 synchronized 代码块里的方法,其他是不会同步执行的。
synchronized 方法是一种粗粒度的并发控制,某一时刻,只能有一个线程执行 synchronized 方法。
synchronized 块则是细粒度的并发控制,只会将块中的代码同步,方法内的其他代码是可以被多个线程同时访问到的
来源: http://www.cnblogs.com/jijiji/p/6900744.html