深入同步访问共享的可变数据分析

如果对共享的可变数据的访问不能同步,其后果非常可怕,即使这个变量是原子可读写的。
下面考虑一个线程同步方面的问题。对于线程同步,Java类库提供了Thread.stop的方法,但是这个方法并不值得提倡,因为它本质上是不安全的。使用轮询(Polling)的方式会更好,例如下面这段程序。


代码如下:

import java.util.concurrent.TimeUnit;
public class StopThread {
 /**
  * @param args
  */

private static boolean stopRequested;

public static void main(String[] args)
  throws InterruptedException{

Thread backgroundThread = new Thread(new Runnable() {

@Override
   public void run() {

int i = 0;
    while(!stopRequested){
     i++;
     System.out.println(i);
    }
   }
  });
  backgroundThread.start();
  TimeUnit.SECONDS.sleep(1);
  stopRequested = true;
 }
}

你可能会认为这个程序在运行大约一秒后,由于主线程把stopRequested设成了true,使得后台的新线程停止,其实不然,因为后台线程看不到这个值的变化,所以会一直无线循环下去,这就是没有对数据进行同步的后果。因此让我们用同步的方式来实现这个任务。


代码如下:

import java.util.concurrent.TimeUnit;
public class StopThread {
 /**
  * @param args
  */

private static boolean stopRequested;

private static synchronized void requestStop(){
  stopRequested = true;
 }
 private static synchronized boolean stopRequested(){
  return stopRequested;
 }

public static void main(String[] args)
  throws InterruptedException{

Thread backgroundThread = new Thread(new Runnable() {

@Override
   public void run() {

int i = 0;
    while(!stopRequested()){
     i++;
     System.out.println(i);
    }
   }
  });
  backgroundThread.start();
  TimeUnit.SECONDS.sleep(1);
  requestStop();
 }
}

这样就实现了数据的同步,值得注意的是,写方法(requestStop)和读方法(stopRequested)都需要被同步,否则仍然不是真正意义上的同步。
另外,我们可以使用volatile这个变量修饰符来更加简单地完成同步任务。


代码如下:

import java.util.concurrent.TimeUnit;
public class StopThread {
 /**
  * @param args
  */

private static volatile boolean stopRequested;

public static void main(String[] args)
  throws InterruptedException{

Thread backgroundThread = new Thread(new Runnable() {

@Override
   public void run() {

int i = 0;
    while(!stopRequested){
     i++;
     System.out.println(i);
    }
   }
  });
  backgroundThread.start();
  TimeUnit.SECONDS.sleep(1);
  stopRequested = true;
 }
}

(0)

相关推荐

  • 深入同步访问共享的可变数据分析

    如果对共享的可变数据的访问不能同步,其后果非常可怕,即使这个变量是原子可读写的.下面考虑一个线程同步方面的问题.对于线程同步,Java类库提供了Thread.stop的方法,但是这个方法并不值得提倡,因为它本质上是不安全的.使用轮询(Polling)的方式会更好,例如下面这段程序. 复制代码 代码如下: import java.util.concurrent.TimeUnit;public class StopThread { /**  * @param args  */ private sta

  • 走进JDK之不可变类String

    文中相关源码: String.java 今天来说说 String. 贯穿全文,你需要始终记住这句话,String 是不可变类 .其实前面说过的所有基本数据类型包装类都是不可变类,但是在 String 的源码中,不可变类 的概念体现的更加淋漓尽致.所以,在阅读 String 源码的同时,抽丝剥茧,你会对不可变类有更深的理解. 什么是不可变类 ? 首先来看一下什么是不可变类?Effective Java 第三版 第 17 条 使不可变性最小化 中对 不可变类 的解释: 不可变类是指其实例不能被修改的

  • ReentrantLock从源码解析Java多线程同步学习

    目录 前言 管程 管程模型 MESA模型 主要特点 AQS 共享变量 资源访问方式 主要方法 队列 node节点等待状态 ReentrantLock源码分析 实例化ReentrantLock 加锁 A线程加锁成功 B线程尝试加锁 释放锁 总结 前言 如今多线程编程已成为了现代软件开发中的重要部分,而并发编程中的线程同步问题更是一道难以逾越的坎.在Java语言中,synchronized是最基本的同步机制,但它也存在着许多问题,比如可重入性不足.死锁等等.为了解决这些问题,Java提供了更加高级的

  • java多线程中线程封闭详解

    线程封闭的概念 访问共享变量时,通常要使用同步,所以避免使用同步的方法就是减少共享数据的使用,这种技术就是线程封闭. 实现线程封闭的方法 1:ad-hoc线程封闭 这是完全靠实现者控制的线程封闭,他的线程封闭完全靠实现者实现.也是最糟糕的一种线程封闭.所以我们直接把他忽略掉吧. 2:栈封闭 栈封闭是我们编程当中遇到的最多的线程封闭.什么是栈封闭呢?简单的说就是局部变量.多个线程访问一个方法,此方法中的局部变量都会被拷贝一分儿到线程栈中.所以局部变量是不被多个线程所共享的,也就不会出现并发问题.所

  • C#多线程用法详解

    目录 一.基本概念 1.进程 2.线程 二.多线程 2.1 System.Threading.Thread类 2.2线程的常用属性 2.2.1 线程的标识符 2.2.2 线程的优先级别 2.2.3 线程的状态 2.2.4 System.Threading.Thread的方法 2.3 前台线程和后台线程 2.4 线程同步 2.5 跨线程访问 2.6 终止线程 三.同步和异步 四.回调 一.基本概念 1.进程 首先打开任务管理器,查看当前运行的进程: 从任务管理器里面可以看到当前所有正在运行的进程.

  • 深入学习C#多线程

    目录 一.基本概念 1.进程 2.线程 二.多线程 2.1System.Threading.Thread类 2.2 线程的常用属性 2.2.1线程的标识符 2.2.2线程的优先级别 2.2.3线程的状态 2.2.4System.Threading.Thread的方法 2.3前台线程和后台线程 2.4线程同步 2.5跨线程访问 2.6终止线程 三.同步和异步 四.回调 获取委托异步调用的返回值 一.基本概念 1.进程 首先打开任务管理器,查看当前运行的进程: 从任务管理器里面可以看到当前所有正在运

  • Go语言并发模型的2种编程方案

    概述 我一直在找一种好的方法来解释 go 语言的并发模型: 不要通过共享内存来通信,相反,应该通过通信来共享内存 但是没有发现一个好的解释来满足我下面的需求: 1.通过一个例子来说明最初的问题 2.提供一个共享内存的解决方案 3.提供一个通过通信的解决方案 这篇文章我就从这三个方面来做出解释. 读过这篇文章后你应该会了解通过通信来共享内存的模型,以及它和通过共享内存来通信的区别,你还将看到如何分别通过这两种模型来解决访问和修改共享资源的问题. 前提 设想一下我们要访问一个银行账号: 复制代码 代

  • Redis实现分布式锁的几种方法总结

    Redis实现分布式锁的几种方法总结 分布式锁是控制分布式系统之间同步访问共享资源的一种方式.在分布式系统中,常常需要协调他们的动作.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁. 我们来假设一个最简单的秒杀场景:数据库里有一张表,column分别是商品ID,和商品ID对应的库存量,秒杀成功就将此商品库存量-1.现在假设有1000个线程来秒杀两件商品,500个线程秒杀第一个商品,

  • 深入解析Python中的线程同步方法

    同步访问共享资源 在使用线程的时候,一个很重要的问题是要避免多个线程对同一变量或其它资源的访问冲突.一旦你稍不留神,重叠访问.在多个线程中修改(共享资源)等这些操作会导致各种各样的问题:更严重的是,这些问题一般只会在比较极端(比如高并发.生产服务器.甚至在性能更好的硬件设备上)的情况下才会出现. 比如有这样一个情况:需要追踪对一事件处理的次数 counter = 0 def process_item(item): global counter ... do something with item

  • 基于redis分布式锁实现秒杀功能

    最近在项目中遇到了类似"秒杀"的业务场景,在本篇博客中,我将用一个非常简单的demo,阐述实现所谓"秒杀"的基本思路. 业务场景 所谓秒杀,从业务角度看,是短时间内多个用户"争抢"资源,这里的资源在大部分秒杀场景里是商品:将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确. 一些可能的实现 刚才提到过,实现秒杀的关键点是控制线程对资源的争抢,根据基本的线程知识,可

随机推荐