`

Java线程同步机制

阅读更多
1、多线程的同步:
1.1、同步机制:
在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生。所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问。

1.2、共享成员变量的例子:
成员变量与局部变量:
成员变量:


如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变量的。

局部变量:


如果一个变量是局部变量,那么多个线程对同一个对象进行操作,每个线程都会有一个该局部变量的拷贝。他们之间的局部变量互不影响。

下面举例说明:
实现了Runnable的线程类:

class MyThread3 implements Runnable{

    //两个线程操作同一个对象,共享成员变量
    //int i;
    @Override
    public void run() {
        //两个线程操作同一个对象,各自保存局部变量的拷贝
        int i = 0;
        while(i<100){
            System.out.println(i);
            i++;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}在main方法中用两个线程操作同一个对象:

public static void main(String[] args) {

    MyThread3 myThread = new MyThread3();
    //下面两个线程对同一个对象(Runnable的实现类对象)进行操作
    Thread thread = new Thread(myThread);
    Thread thread2 = new Thread(myThread);
    //各自保存局部变量的拷贝,互不影响,输出200个数字
    thread.start();
    thread2.start();
}这里如果把i变成成员变量,则输出100个数字。

1.3、共享资源导致的读取错误
下面举个例子,两个线程共用一个Number对象,通过Number类的getNumber方法获取数据,读取数据并改写时,发现了重复读操作:

首先创建一个Number类:

class Number{
    private int number = 10;
    public String getNumber(int i){
        if(number > 0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            number -= i;
            return "取出"+i+"成功,剩余数量:"+number;
        }
        return "取出"+i+"失败,剩余数量:"+number;
    }
}线程类,在线程类中的私有属性包含了Number类的引用:

class MyThread4 extends Thread{

    //两个线程操作同一个对象,共享成员变量
    Number number;
    public MyThread4(Number number){
        this.number = number;
    }
    @Override
    public void run() {
        System.out.println(number.getNumber(8));
    }
}在main函数中创建两个线程类,包含了同一个Number类实例的引用:

public static void main(String[] args) {

    Number number = new Number();
    //两个线程操作同一个对象,共享对象number的成员变量number
    MyThread4 myThread = new MyThread4(number);
    MyThread4 myThread2 = new MyThread4(number);
    myThread.start();
    myThread2.start();
}这样,当第一个线程读取Number中的number变量时先保存下来再休眠0.1秒,然后第二个线程再读取number变量并保存,此时两个线程保存了同样的数字,在修改时,也就导致修改了同一个数字两次。

2、同步机制的实现:
2.1、使用synchronized关键字创建synchronized方法:
使用synchronized关键字,该关键字修饰的方法叫做同步方法。

Java中每个对象都有一个锁或者称为监视器,当访问某个对象的synchronized方法时,表示将该对象上锁,而不仅仅是为该方法上锁。

这样如果一个对象的synchronized方法被某个线程执行时,其他线程无法访问该对象的任何synchronized方法(但是可以调用其他非synchronized的方法)。直至该synchronized方法执行完。

静态的synchronized方法调用情况:
当调用一个对象的静态synchronized方法时,它锁定的并不是synchronized方法所在的对象,而是synchronized方法所在对象对应的Class对象。这样,其他线程就不能调用该类的其他静态synchronized方法了,但是可以调用非静态的synchronized方法。

结论:执行静态synchronized方法锁方法所在对象,执行非静态synchronized方法锁方法所在对象对应的Class对象。

下面是多线程调用静态的方法的例子,由于锁定了方法所在对象对应的Class对象,其他线程无法调用该方法所在对象其他的静态synchronized方法:

/**
* 定义一个类,包含了线程类需要调用的方法
*/
class Compute1{
    //这时如果某个线程调用该方法,
    //将锁定synchronized方法所在对象对应的class对象,
    //而不是锁定synchronized方法所在对象
    public synchronized static void execute(){
        for(int i = 0; i<100; i++){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("compute1:execute1 " + i++);
        }
    }
    public synchronized static void execute2(){
        for(int i = 0; i<100; i++){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("compute1:execute2 " + i++);
        }
    }
}main方法中两个线程分别调用同一个对象的两个static synchronized方法:

public static void main(String[] args) {
    Compute1 com = new Compute1();
    Thread thread1 = new Thread1(com);
    Thread thread2 = new Thread2(com);
    thread1.start();
    thread2.start();
}一次只能调用一个静态方法,直到执行完成。

2.2、使用synchronized创建同步代码块:
通过使用synchronized同步代码块,锁定一个对象,该对象作为可执行的标志从而达到同步的效果:

/**
* 定义一个类,包含了线程类需要调用的方法
*/
class Compute1{
    //通过同步代码块锁定object1对象进行锁定了其他同样的synchronized代码块
    private Object object1 = new Object();
    public void execute(){
        synchronized(object1){
            for(int i = 0; i<100; i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("compute1:execute1 " + i++);
            }
        }

    }
    public synchronized void execute2(){
        synchronized(object1){
            for(int i = 0; i<100; i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("compute1:execute2 " + i++);
            }
        }
    }
}如果想要使用synchronized同步代码块达到和使用synchronized方法同样的效果,可以锁定this引用:

synchronized(this){
    …
}2.3、synchronized方法和synchronized同步代码块的区别:
synchronized同步代码块只是锁定了该代码块,代码块外面的代码还是可以被访问的。

synchronized方法是粗粒度的并发控制,某一个时刻只能有一个线程执行该synchronized方法。

synchronized同步代码块是细粒度的并发控制,只会将块中的代码同步,代码块之外的代码可以被其他线程同时访问。

分享到:
评论

相关推荐

    java的线程同步机制synchronized关键字的理解_.docx

    Java 线程同步机制中 synchronized 关键字的理解 Java 的线程同步机制是为了解决多个线程共享同一片存储空间所带来的访问冲突问题。其中,synchronized 关键字是 Java 语言中解决这种冲突的重要机制。 ...

    Java多线程同步机制研究分析.pdf

    Java多线程同步机制研究分析 Java多线程同步机制是Java编程语言中的一种机制,它允许多个线程同时执行,提高了系统资源的利用率和安全性。但是,多线程中最重要的问题是线程的同步和共享资源的访问保护。本文通过对...

    Java线程同步机制_动力节点Java学院整理

    Java线程同步机制是Java多线程编程中的关键概念,主要用来解决多个线程并发访问共享资源时可能出现的安全问题。当多个线程试图同时修改同一数据时,如果没有适当的同步措施,就可能导致数据不一致或者出现意外的结果...

    Java多线程同步机制的应用分析.pdf

    "Java多线程同步机制的应用分析" Java多线程同步机制的应用分析是指在Java语言中,如何使用同步机制来保护临界区,以避免多线程之间的冲突和错误。该机制通过管程机制和同步语法来保护临界区,使得多线程可以安全...

    Java线程同步例子.pdf

    在Java中,线程同步是保证多线程安全...上述Java线程同步例子中涉及到的代码虽然是片段,但涵盖了线程同步处理的多个重要方面,帮助我们理解和使用Java线程同步机制,以及在设计和实现多线程应用程序时的实践和技巧。

    java 线程同步 信号量控制同步

    线程同步机制是 Java 编程中的一种重要机制,用于控制多个线程之间的资源访问顺序,以避免线程之间的冲突和数据不一致。开发者需要牢牢记住线程同步的四点要素,即线程同步就是线程排队,共享资源需要同步,变量需要...

    Java多线程同步.pdf

    "Java多线程同步.pdf" Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。...Java多线程同步机制是Java语言中的一种重要机制,用于确保多线程程序的正确执行。

    Java多线程同步机制在售票系统的实现

    ### Java多线程同步机制在售票系统的实现 #### 一、引言 随着计算机硬件的发展,多核处理器已经成为主流配置,这为多线程编程提供了更广阔的应用场景。多线程能够充分利用多核处理器的优势,提高程序的并发性和...

    java线程同步详解

    了解并正确使用线程同步机制对于编写高效、可靠的多线程程序至关重要。在实际编程中,应尽量减少同步的范围,提高程序的并发性能。同时,理解和避免死锁、活锁和饥饿等并发问题也是开发者必备的技能。

    基于Java多线程同步的安全性研究.pdf

    文章首先介绍了Java多线程同步的必要性和重要性,然后讨论了Java多线程同步机制的实现方法,包括使用synchronized关键字和Java.util.concurrent.locks包中的Lock对象。接着,文章讨论了Java多线程同步机制中可能出现...

    Java 线程同步调用

    在深入探讨Java线程同步调用这一主题之前,我们首先需要理解线程同步的基本概念及其在多线程环境中的重要性。线程同步是多线程编程中的一个关键概念,它确保了多个线程在访问共享资源时不会发生冲突,避免了数据不...

    JAVA多线程同步机制及其应用.doc

    Java多线程同步机制及其应用是Java编程中至关重要的一环,尤其在开发高并发、高性能的应用程序时,理解并掌握这些机制是必不可少的。本文档详细介绍了Java中多线程的相关概念、创建方式、线程管理、同步机制以及一个...

    java线程同步及通信

    Java线程同步与通信是多线程编程中的关键概念,用于解决并发访问共享资源时可能出现的数据不一致性和竞态条件问题。以下将详细介绍这两个主题,以及如何通过代码示例进行演示。 1. **线程同步**: 线程同步是确保...

    JAVA 线程实现数据库的主从同步更新

    Java线程提供了异常处理机制,可以使用try-catch-finally块来捕获和处理异常。如果同步失败,可能需要回滚主数据库的事务,或者标记异常并尝试在后续同步周期中再次处理。 5. **性能优化**: 为提高同步效率,可以...

    Java多线程同步机制在网络售票系统中的应用.zip

    Java多线程同步机制在网络售票系统中的应用是一个关键的话题,特别是在高并发环境下,如网络售票系统,正确地处理多线程同步是确保数据一致性、避免资源竞争和死锁的重要手段。下面将详细介绍Java多线程同步机制以及...

    操作系统实验 多线程同步与互斥 java编写 有界面

    在“操作系统实验 多线程同步与互斥 java编写 有界面”的实验中,可能需要设计一个图形用户界面(GUI),通过按钮或事件触发线程的创建和同步操作,直观地展示线程间的交互和同步效果。例如,可以模拟银行账户转账,...

    JNI 多线程同步机制的源码实现

    JNI(Java Native Interface)是Java平台提供的一种标准接口,允许Java代码和其他语言写的代码进行交互。在多线程环境中,当涉及到与本地代码...理解和掌握JNI的多线程同步机制对于Java开发者深入系统级编程至关重要。

    基于JAVA线程机制研究生产者-消费者问题.zip

    在Java编程中,线程是并发执行的基本单元,它允许程序在同一时间处理多个任务。生产者-消费者问题是多线程编程中的...生产者-消费者问题的解决方式不仅有助于提升程序的并发能力,还能够加深对Java线程同步机制的理解。

Global site tag (gtag.js) - Google Analytics