美文网首页
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