java中synchronized的使用和理解

来源:互联网 发布:为什么要激活windows 编辑:程序博客网 时间:2024/05/29 17:20

首先说一下Java的同步机制:保证在同一时间只有一个线程可以操作对应资源,避免多个线程同时访问相同资源发生冲突。synchronize是java中的一个关键字,它是一种同步锁,可以实现同步机制。
synchronized常用的几种方式:
1. synchronized修饰普通方法
2. synchronize修饰静态方法
3. synchron修饰代码块
下面我把自己写的demo来进行说明
1:synchronized修饰普通方法

public class A {    int num = -1;    public A() {        num = 0;    }    public synchronized void a() {        for (int i = 0; i < 5; i++) {            num += 1;            try {                Thread.sleep(10);           System.out.println(Thread.currentThread().getName() +">>>>>>>>>>"+ num);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }
public class Main {    public static void main(String[] args) {        A a = new A();    new Thread(new Runnable() {        public void run() {            a.a();        }    }).start();    new Thread(new Runnable() {        public void run() {            a.a();        }    }).start();    }}

打印结果:
Thread-0>>>>>>>>>>1
Thread-0>>>>>>>>>>2
Thread-0>>>>>>>>>>3
Thread-0>>>>>>>>>>4
Thread-0>>>>>>>>>>5
Thread-1>>>>>>>>>>6
Thread-1>>>>>>>>>>7
Thread-1>>>>>>>>>>8
Thread-1>>>>>>>>>>9
Thread-1>>>>>>>>>>10
恩,不错,确实是实现了在同一时间内,只有一个线程能访问对应的资源,其他的线程必须的等其结束了才能开始运行。
好,那么我修改一下main中的代码呢?

public class Main {    public static void main(String[] args) {        A a1 = new A();        A a2= new A();    new Thread(new Runnable() {        public void run() {            a1.a();        }    }).start();    new Thread(new Runnable() {        public void run() {            a2.a();        }    }).start();    }}

打印出来的结果是:
Thread-0>>>>>>>>>>1
Thread-1>>>>>>>>>>1
Thread-0>>>>>>>>>>2
Thread-1>>>>>>>>>>2
Thread-0>>>>>>>>>>3
Thread-1>>>>>>>>>>3
Thread-1>>>>>>>>>>4
Thread-0>>>>>>>>>>4
Thread-0>>>>>>>>>>5
Thread-1>>>>>>>>>>5
咦,这个结果怎么是这样?可以看出两个线程开启后,开始进行交叉运行。这样不对啊!!!应该等第一个线程结束,第二个线程才能开始运行啊。那么问题就来了,那么我就开始说一下这个事情。
synchronize修饰普通的方法时,是对象锁。也就是说在多线程中使用同一个对象访问synchronized修饰的方法可以达到同步的效果。但是如果在不同的线程中使用不同对象去调用其修饰的方法则达不到同步的效果。

2.修饰静态方法
public class A {    static int num = -1;    byte[] lock = new byte[0];    public A() {        num = 0;    }    public static synchronized void a() {        for (int i = 0; i < 5; i++) {            num += 1;            try {                Thread.sleep(10);                System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>"                        + num);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }
public class Main {    public static void main(String[] args) {    new Thread(new Runnable() {        public void run() {            A.a();        }    }).start();    new Thread(new Runnable() {        public void run() {            A.a();        }    }).start();    }}

打印结果:
Thread-0>>>>>>>>>>0
Thread-0>>>>>>>>>>1
Thread-0>>>>>>>>>>2
Thread-0>>>>>>>>>>3
Thread-0>>>>>>>>>>4
Thread-1>>>>>>>>>>5
Thread-1>>>>>>>>>>6
Thread-1>>>>>>>>>>7
Thread-1>>>>>>>>>>8
Thread-1>>>>>>>>>>9
synchronized修饰的静态方法,这种情况下的锁是包含这个方法的类的锁,也是这个类对象的锁。所以多线程访问时,可以达到同步的效果。
3.修饰代码块

public class A {    static int num = -1;    byte[] lock = new byte[0];    public A() {        num = 0;    }    public void printfLog() {        synchronized (lock) {            for (int i = 0; i < 5; i++) {                num += 1;                try {                    Thread.sleep(10);        System.out.println(Thread.currentThread().getName()                            + ">>>>>>>>>>" + num);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }
public class Main {    public static void main(String[] args) {        A a1 = new A();        A a2 = new A();    new Thread(new Runnable() {        public void run() {            a1.printfLog();        }    }).start();    new Thread(new Runnable() {        public void run() {            a2.printfLog();        }    }).start();    }}

打印结果:
Thread-0>>>>>>>>>>2
Thread-1>>>>>>>>>>3
Thread-0>>>>>>>>>>4
Thread-1>>>>>>>>>>5
Thread-0>>>>>>>>>>6
Thread-1>>>>>>>>>>7
Thread-0>>>>>>>>>>8
Thread-1>>>>>>>>>>9
Thread-0>>>>>>>>>>10
Thread-1>>>>>>>>>>10
这中结果和synchronize修饰的普通方法类似。在多线程中不同对象的进行调用,不能实现同步的效果。
注意:
1.在多线程中同一个对象进行调用,可以实现同步的效果 .可自行尝试一下。
2.将lock换成this时,打印的效果是一样的。
那么我将代码改动一下呢?

public class A {    static int num = -1;    byte[] lock = new byte[0];    public A() {        num = 0;    }    public void printfLog() {        synchronized (A.class) {            for (int i = 0; i < 5; i++) {                num += 1;                try {                    Thread.sleep(10);                    System.out.println(Thread.currentThread().getName()                            + ">>>>>>>>>>" + num);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }

打印结果如下:
Thread-0>>>>>>>>>>1
Thread-0>>>>>>>>>>2
Thread-0>>>>>>>>>>3
Thread-0>>>>>>>>>>4
Thread-0>>>>>>>>>>5
Thread-1>>>>>>>>>>6
Thread-1>>>>>>>>>>7
Thread-1>>>>>>>>>>8
Thread-1>>>>>>>>>>9
Thread-1>>>>>>>>>>10
所以这样的效果跟synchronize修饰静态方法一样。这样就可以在不同线程中不同的对象调用时实现同步的效果。

下面说一下synchronize修饰方法和代码块的区别:
synchronize修饰方法时,控制整个方法。
synchronize修饰代码块时,只控制代码块(只有代码块之内的才能实现同步效果)。而对于代码块之外的代码,则不受控制(也就是不能实现同步的效果)。
简单一点说就是:synchronize修饰代码块时,更加灵活精确。

阅读全文
1 0
原创粉丝点击