对共享可变数据的同步访问

本文深入探讨Java线程同步的意义、实现方式及其在保证数据一致性、互斥访问中的作用。通过实例分析,展示了同步机制如何确保多个线程在访问共享资源时的数据正确性和线程安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般认为同步就是一般的互斥行文。不是很全面。
同步的意义:同步不仅可以阻止一个线程看到对象处于不一致的状态中,它还可以保证通过一系列看似顺序执行的状态转变序列,对象从一种一致的状态变迁到另外一种一致的状态。每一个线程进入到一个被同步的方法或是代码块的时候,它会看到由同一个锁控制的以前所有状态转变的结果。当线程退出了这个被同步的区域之后,任何线程在进入到由这同一把锁同步的区域时,它就可以看到由前面那个线程带来的状态转变(如果有状态转变的话)。也就是代码是固定的,变量的地址,或是值变量也是固定的,不同的线程会造成数据被修改的情况,第2个线程进入就会看到被修改的内存值域。

JAVA语言保证读或者写一个变量是原子的,除非这个变量类型为long或是double.也就是说,读入一个非long或double类型的变量,可以保证返回值一定是某个线程保存在该变量中的,即使多个线程在没有同步的情况下并发修改这个变量,也是如此。

有些人说,为了提高性能,在读或写原子数据的时候,你应该避免使用同步。其实这个建议是非常危险而且是错误的。虽然原子性保证了一个线程在读取原子数据的时候,不会看到一个随机的数值,但是它并不保证一个线程写入的值对于另外一个线程是可见的:为了在线程之间可靠的通信,以及为了互斥访问,同步是需要的。

以下代码就可以看出来:
/**
 *
 */
package thread;

/**
 * 单例的Test类,保证唯一性。
 * @author Administrator
 *
 */
public class Test {
   
    private int flag=0;
    private static Test temp=null;
   
    public synchronized void method(){
        flag=flag+1;
        System.out.println(flag);
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
   
    public static Test getInstance(){
        if(temp==null){
            temp=new Test();
            return temp;
        }
        return temp;
    }
}

这个类是执行一个方法method,该方法要被多次调用。
/**
 *
 */
package thread;

/**
 * 实例一个单例的test对象启动线程,调用test.method同步方法。
 * @author Administrator
 *
 */
public class ThreadTemp extends Thread{

    public void run(){
        Test test=Test.getInstance();
        test.method();
    }
}
这个类是启动线程的,他使用的单例,让这个test对象成为唯一的共享对象,包括对象的值域。

/**
 *
 */
package thread;

/**
 * 开启两个线程去访问单例的test,造成域被改变。
 * @author Administrator
 *
 */
public class ThreadFactory {

    public static void main(String[] args) {
        Thread t1=new ThreadTemp();
        t1.start();
        Thread t2=new ThreadTemp();
        t2.start();
    }
}
开始访问可以看到第2个线程进入的时候值域flag已经是1了。
所以打印出来是1,2.
所以JAVA线程的特性我们应该引起注意。这个是线程安全的,当你把method方法的synchronized取消,然后在主函数调用的地方改成循环实例线程,并且把sleep也去掉。你将看到奇怪的现象。这里就是竞争造成的。

记住一句话:无论任何时候当多个线程共享可变数据的时候,每个读或写数据的线程必须获得一把锁,而这个锁只能是对象锁。如果没有同会察到。而且这样的错误,是很难调试和重现的,因为线程调试是很麻烦的。他们是高度依赖JVM和操作系统硬件平台。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值