美文网首页
10、多线程之synchronized关键字

10、多线程之synchronized关键字

作者: 24_yu | 来源:发表于2017-11-11 14:11 被阅读0次

    synchronized是java中的关键字,是一中同步锁。修饰的对象有以下几种:
    1、修饰一个代码块:被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
    2、修饰一个方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。
    3、修饰一个静态的方法:作用范围是整个静态方法,作用的对象是这个类的所有对象。
    4、修饰一个:其作用的范围是synchronized后面括号部分,最用对象和静态方法一样,是这个类的所有对象。

    一、修饰一个代码块

    package com.multithread.test;
    
    public class SyncThread implements Runnable{
        
        private static int count;
        
        public  SyncThread() {
            count = 0;
        }
        @Override
        public void run() {
            
            synchronized(this){
                for (int i = 0; i < 5; i++){
                    System.out.println(Thread.currentThread().getName()+":"+(count++));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        public int getCount(){
            return count;
        }
    }
    
    package com.multithread.learning.Main;
    
    import com.multithread.test.SyncThread;
    
    public class MainSyncThread {
    
        public static void main(String[] args) {
            
            SyncThread st1 = new SyncThread();
            
            new Thread(st1,"SyncThread1").start();
            new Thread(st1,"SyncThread2").start();
        }
    
    }
    

    SyncThread1:0
    SyncThread1:1
    SyncThread1:2
    SyncThread1:3
    SyncThread1:4
    SyncThread2:5
    SyncThread2:6
    SyncThread2:7
    SyncThread2:8
    SyncThread2:9

    当两个并发线程(thread1和thread2)访问同一个对象(syncThread)中的synchronized代码块时,在同一时刻只能有一个线程得到执行,另一个线程受阻塞,必须等待当前线程执行完这个代码块以后才能执行该代码块。Thread1和thread2是互斥的,因为在执行synchronized代码块时会锁定当前的对象,只有执行完该代码块才能释放该对象锁,下一个线程才能执行并锁定该对象。
    
    稍微修改一下:创建两个对象,也就是说有**两把锁**,结果如下:
    ```java
            SyncThread st1 = new SyncThread();
            SyncThread st2 = new SyncThread();
            
            new Thread(st1,"SyncThread1").start();
            new Thread(st2,"SyncThread2").start();
    
    SyncThread1:0
    SyncThread2:1
    SyncThread1:3
    SyncThread2:2
    SyncThread1:4
    SyncThread2:5
    SyncThread1:6
    SyncThread2:6
    SyncThread1:7
    SyncThread2:7
    

    两把锁分别锁定syncThread1对象和syncThread2对象,两把锁互不干扰,不形成互斥,两个线程同时进行

    此处的this相当于一个对象,指向当前对象(如此便相当于锁定了一个方法)。如果需要对一个对象加锁,如下:

    syncThreadObject s = new syncThreadObject("黄",23);
            
            SyncThread st1 = new SyncThread(s);
            for (int i = 0; i < 5; i++) {
                new Thread(st1, "   SyncThread+"+i).start();
            }
    
    @Override
        public void run() {
            
            synchronized(s){
                for (int i = 0; i < 5; i++){
                    System.out.println(Thread.currentThread().getName()+":"+s.toString()+(count++));
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    

    循环创建对象st1的线程5个,执行,每个线程访问st1对象时,其他试图访问st1对象的线程将会阻塞,直到该线程访问st1对象结束。也就是说谁拿到那个锁谁就可以运行锁内控制的代码。
    因此在类似于需要多个线程按顺序打印序号时,便可以让多个线拥有共同的一个锁,或者使用wait/notify来控制。

    二、修饰一个方法

    修饰一个方法很简单,就是在方法前面加上synchronized关键字,public synchronized void method(){}。
    注意:synchronized方法不能被继承,也就是覆写了父类的syn方法,默认情况下不是同步的,必须显示地在子类的这个方法加上synchronized关键字才行.

    三、修饰一个静态方法

    @Override
        public void run() {
            
            method();
        }
        public synchronized static void method(){
            for (int i = 0; i < 5; i++){
                System.out.println(Thread.currentThread().getName()+":"+(count++));
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
            SyncThread st1 = new SyncThread(s);
            SyncThread st2 = new SyncThread(s);
            SyncThread st3 = new SyncThread(s);
            
            new Thread(st1, "A").start();
            new Thread(st2, "B").start();
            new Thread(st3, "C+").start();
    
    A:0
    A:1
    A:2
    A:3
    A:4
    C+:5
    C+:6
    C+:7
    C+:8
    C+:9
    B:10
    B:11
    B:12
    B:13
    B:14
    

    即使是创建了多个对象,又多个线程分别访问每个对象,但还是保持了线程同步。因为run中调用了静态方法method,而静态方法时属于类的,因此,这些对象拥有的锁是同一把锁

    四、修饰一个类

    类似于静态方法。此处不再阐述。

    相关文章

      网友评论

          本文标题:10、多线程之synchronized关键字

          本文链接:https://www.haomeiwen.com/subject/usyimxtx.html