Java多线程基础篇(03)-synchronized关键字

本秂侑毒 提交于 2020-02-28 21:19:46

1.引言

    基本上所有的并发模式再解决线程冲突的时候,都是采用序列化访问共享资源的方案。这意味着在给定时刻只允许一个任务访问共享资源。通常这是通过在代码前面添加一条锁语句来实现的,这就使得在一段时间内只有一个任务可以运行这段代码。因为锁语句产生了一种互相排斥的效果,锁着这种机制常常被称为互斥量。

    Java以提供关键字synchronized的形式,为防止资源冲突提供了内置支持。当任务要执行被synchronized关键字保护的代码片段的时候,它将检查锁是否可用,然后获取锁,执行代码,释放锁

    共享资源一般是以对象形式存在的内存片段,但也可以是文件、输入/输出端口,或者是打印机设备。要控制对共享资源的访问,得先把它包装进一个对象。然后把所有要访问这个资源的方法标记为synchronized。如果某个任务处于一个对标记为synchronized方法的调用中,那么在这个线程从该方法返回之前,其他所有要调用类中任何标记synchronized方法的线程都会被阻塞。

2.synchronized原理

    在Java中,每一个对象有且仅有一个同步锁。这也意味着,同步锁依赖对象而存在。当我们调用某个对象的synchronized修饰的方法时,就获取了该对象的同步锁。例如synchronized(obj)方法就获取了obj这个对象的同步锁。

    不同线程对同步锁的访问是互斥的。也就是说,在某一个时刻,对象的同步锁只能被一个线程获取到!其他要获取该锁的线程都会被阻塞。知道线程释放了该锁,其他线程才能去获取同步锁,然后执行代码块。详细的synchronized工作原理请见博客:synchronized实现原理

3.synchronized基本用法

    synchronized语句计算一个对象引用,试图对该对象完成锁操作,并且在完成所操作前停止处理。当锁操作完成,synchronized语句体得到执行。当语句体执行完毕(无论正常与否),解锁操作自动执行。synchronized经常与方法连用。

public synchronized void function(){
    //保护函数
}

    一种比较好的办法是,如果某个变量由一个线程赋值,并由别的线程引用或赋值,那么所有对该变量的访问都必须在某个synchronized语句或者synchronized方法内,

synchronized(this){
    //保护代码块
}

    有了synchronized关键字,多线程程序的运行结果将变得可以控制。synchronized关键字用于保护共享数据。所以编程时分清共享数据很重要

4.synchronized代码演示

4.1 synchronized为对象实例加锁

class MyRunable implements Runnable {
    
    @Override
    public void run() {
        synchronized(this) {
            try {  
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(100); // 休眠100ms
                    System.out.println(Thread.currentThread().getName() + " loop " + i);  
                }
            } catch (InterruptedException ie) {  
            }
        }  
    }
}

public class Demo1_1 {

    public static void main(String[] args) {  
        Runnable demo = new MyRunable();     
        Thread t1 = new Thread(demo, "t1");
        Thread t2 = new Thread(demo, "t2");
        t1.start();
        t2.start();
   } 
}

运行结果:

t1 loop 0
t1 loop 1
t1 loop 2
t1 loop 3
t1 loop 4
t2 loop 0
t2 loop 1
t2 loop 2
t2 loop 3
t2 loop 4

结果说明:

run()方法中存在synchronized(this)代码块,而且t1和t2都是基于Runnable对象创建的线程。这就意味着,我们可以将synchronized(this)中的this看作是Runnable对象;因此t1和t2共享demo对象的同步锁。所以,当一个线程运行的时候,另外一个线程必须等待“运行中的线程”释放同步锁之后才能运行。特此说明:synchronized(this)中的this是指当前的类对象,即synchronized(this)所在的类对应的当前对象。它的作用是获取“当前对象的同步锁”。

4.2 synchronized为方法加锁

    synchronized方法是用synchronized修饰的方法,具体示例这里不给出了,有兴趣的童鞋,可以参照4.1给方法加上synchronized修饰。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!