java synchronized关键字

synchronized关键字用于多线程同步,其具有以下作用:
1. 确保线程互斥的访问同步代码
2. 保证共享变量的修改能够及时可见
3. 有效解决重排序问题

其主要有三种用法:
1. 修饰普通方法
2. 修饰静态方法
3. 修饰代码块

测试代码:

public class C{

    private static ArrayList list=new ArrayList<>();

    public void noSyn() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+" "+"no Syn");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }

    }

    public synchronized void normalSyn1() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+" "+"normal Syn1 ");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }

    }

    public static void noSynStatic() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+" "+"no Syn static");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }

    }

    public static synchronized void staticSyn() {
        for(int i=0;i<5;++i){
            //list.add(i);
            System.out.println(Thread.currentThread().getName()+" "+"static syn "+list);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }

    }

    public void staticString1(){
        synchronized (list) {
            for(int i=0;i<5;++i){
                list=new ArrayList<>();
                System.out.println(Thread.currentThread().getName()+" "+"static integer1 "+list);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
            }
        }
    }

    public void staticString2(){
        synchronized (list) {
            for(int i=0;i<5;++i){
                System.out.println(Thread.currentThread().getName()+" "+"static integer2 "+list);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized void normalSyn2() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+" "+"normal Syn2");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }
    }
}

其特点如下:
1.synchronized修饰普通方法methodA时,在不同线程中使用同一对象调用方法methodA,这样会导致先获取该对象锁的线程先执行,其他线程受阻塞。

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.normalSyn();  
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c.normalSyn();
            }
        }).start();

    }

java synchronized关键字_第1张图片

2.synchronized修饰普通方法methodA、methodB时,在不同线程中使用同一对象。在线程A中调用methodA,在线程B中调用methodB,这样会导致先获取对象锁的线程先执行,其他线程受阻塞。这表明,synchronized修饰普通方式时,锁住的是对象。当某一个线程获取到该对象锁时,其他线程就不能执行需要该对象锁的方法(即synchronized修饰的普通方法,代码块上为this的synchronized代码块)

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.normalSyn1(); 
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c.normalSyn2();
            }
        }).start();

    }

结果:
java synchronized关键字_第2张图片

3.synchronized修饰普通方法methodA时,在不同线程中使用不同对象调用该方法,这样会导致各线程按CPU调度进行,没有发送阻塞。这表明,不同对象有不同的对象锁,互不影响。

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.normalSyn1(); 
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c1.normalSyn1();
            }
        }).start();

结果:
java synchronized关键字_第3张图片

4.synchronized修饰普通方法methodA时,在不同线程中同一对象,在线程A中调用methodA,在线程B中调用非synchronized的方法methodB,这样会导致各线程按CPU调度进行,没有发送阻塞。这表明,没有锁的方法不会受到对象锁影响。

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.normalSyn1(); 
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c.noSyn();
            }
        }).start();

    }

结果:
java synchronized关键字_第4张图片

5.synchronized修饰静态方法时,在不同线程中使用该类的不同对象调用该方法时,这样会导致先获取类锁的线程先执行,其他线程阻塞。

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.staticSyn();
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c1.staticSyn();
            }
        }).start();

    }

结果:
java synchronized关键字_第5张图片

6.synchronized修饰普通方法methodA、静态方法methodB时,在不同线程中使用同一对象。在线程A中调用methodA,在线程B中调用methodB,这样会导致线程按CPU调度进行,各不影响。因为普通方法锁的是对象,静态方法锁的是类,两者互不干扰。

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.staticSyn();
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c.normalSyn1();
            }
        }).start();

    }

结果:
java synchronized关键字_第6张图片

7.在方法methodA中用synchronized修饰代码块上的静态变量,synchronized修饰静态方法methodB,在不同线程中使用同一对象。在线程A中调用methodA,在线程B中调用methodB,这样会导致线程按CPU调度进行,各不影响。这表明虽然synchronized修饰的是静态变量,但它锁的是该变量;而synchronized修饰静态方式锁的是类,这样它们还是会互不影响。所以在synchronized锁变量时,必须要注意其在其他方法中的控制。
C类中方法staticSyn有所改变:

public static synchronized void staticSyn() {
        for(int i=0;i<5;++i){
            System.out.println(Thread.currentThread().getName()+" "+"static syn "+list);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
        }

    }
public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.staticString2();
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c.staticSyn();
            }
        }).start();

    }

结果:
java synchronized关键字_第7张图片

8.在方法methodA中用synchronized修饰代码块上的静态变量,在方法methodB中用synchronized修饰代码块上的同样的静态变量,在不同线程中使用同一对象。在线程A中调用methodA,在线程B中调用methodB,这样会导致先获取类锁的线程先执行,其他线程阻塞。前提是在先执行的线程中没有改变该静态变量的内存地址。若改变了,那么线程会按CPU调度运行。因为synchronized锁的是变量的那个内存位置,若后面改变了该变量的内存位置,在其他方法中比对当前位置与被锁位置不一致,则会执行。

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.staticString1();      
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c.staticString2();
            }
        }).start();

    }

结果:
java synchronized关键字_第8张图片

顺序改变一下:(先执行的线程没有改变地址)

public static void main(String []ags) throws Exception{
        final C c=new C();
        final C c1=new C();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根
                c.staticString2();          
            }
        }).start();
        new Thread(new Runnable() {         
            @Override
            public void run() {
                // TODO 自动生成的方法存根       
                c.staticString1();
            }
        }).start();

    }

结果:
java synchronized关键字_第9张图片

你可能感兴趣的:(java,多线程,多线程)