ARTS 01

ARTS 即 Algorithm,Review,Technology,Share。
本篇是本系列的第一篇,作者现在正处于大学阶段,所以很多部分还是会很弱的,希望各位谅解。这里只是想养成一个习惯

  • 本次Algorithm是 Leetcode12 # 整数转罗马数字 ,难度为中等
  • Review 暂时为空
  • Technology 为 Volatile关键字实现原理
  • Share 为 Markdown的一些基本用法

8e3232eaefab61b8f48fbacf6fba178d.jpg

Algorithm

Leetcode12 c

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。
示例 1:
输入: 3
输出: "III"

   if(num<1 || num >3999) return null;
    int[] values = { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 
     4, 1 };
    String[] strs = { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X",           
    "IX", "V", "IV", "I" };

    
    StringBuilder sb = new StringBuilder();

    for (int i = 0; i < values.length; i++) {
        while (num >= values[i]) {
            num -= values[i];
            sb.append(strs[i]);
        }
    }
    return sb.toString();`

最暴力的解法,把5~1000的都定义好,然后直接通过转换即可,这里就不用多说咯


Review

这里暂时为空,


Technology

1.JAVA并发编程中的三个概念

  • 1.原子性
    即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
    比如:从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。
    所以这2个操作必须要具备原子性才能保证不出现一些意外的问题。

同样地反映到并发编程中会出现什么结果呢?
假如为一个32位的变量赋值过程不具备原子性的话,会发生什么后果?
i = 5;
一个线程执行到这个语句时,我暂且假设为一个32位的变量赋值包括两个过程:为低16位赋值,为高16位赋值。

那么就可能发生一种情况:当将低16位数值写入之后,突然被中断,而此时又有一个线程去读取i的值,那么读取到的就是错误的数据。

  • 2.可见性
    可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
  • 3.有序性
    有序性:即程序执行的顺序按照代码的先后顺序执行。
    Java 底层会涉及重排序
    Volatile关键字Java并发编程里面常见的,volatile关键智能保证可见性和有序性,并不能保证原子性
    public class VolatileTest {
       public static volatile int race = 0;

      public static void increase() {
          race++;
      }

      private static final int THREADS_COUNT = 20;

      public static void main(String[] args) {
          Thread[] threads = new Thread[THREADS_COUNT];
          for (int i = 0; i < THREADS_COUNT; i++) {
              threads[i] = new Thread(new Runnable() {
                  @Override
                  public void run() {
                      for (int i = 0; i < 1000; i++) {
                          increase();
                      }
                  }
              });
              threads[i].start();
          }

          // 等待所有累加线程都结束
          while (Thread.activeCount() > 1)
              Thread.yield();

          System.out.println(race);
      }
  }

这段代码发起了20个线程,每个线程对race变量进行1000次自增操作,如果这段代码能够正确并发的话,最后输出的结果应该是20000。读者运行完这段代码之后,并不会获得期望的结果,而且会发现每次运行程序,输出的结果都不一样,都是一个小于20000的数字。显然Volatile关键不保证原子性

解决这个问题,方法同步块包裹起来当然是一个办法,但是使用Atomic的原子自增运算,那效率将会提高许多

 import java.util.concurrent.atomic.AtomicInteger;

public class AtomicTest{

    public static AtomicInteger race=new AtomicInteger(0);

        public static void increase(){

        race.incrementAndGet();

    }

        private static final int THREADS_COUNT=20;

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

            Thread[]threads=new Thread[THREADS_COUNT];

            for(int i=0;i1)
                Thread.yield();
            System.out.println(race);
        }
}

运行结果如下:
200000
使用AtomicInteger代替int后,程序输出了正确的结果,这一切都是要归功于 incrementAndGet()方法的原子性。它的实现其实非常简单

/**
*Atomically increment by one the current value.
*@return the updated value
*/

public final int incrementAndGet(){

    for(;){

    int current=get();

    int next=current+1;

    if(compareAndSet(current,next))

    return next;

    }

}

incrementAndGet()方法在一个无限循环中,不断尝试将比当前值大1的新值赋给自己。如果失败了,那就说明在执行“获取,设置”操作的时候只已经有了修改,于是再次进行下一次操作,知道成功为止。
  尽管CAS(Compare And Swap)看起来很美,但显然这种操作无法涵盖互斥同步的所有使用场景,并且CAS从语义上来说并不是完美的,存在一个逻辑上的漏洞:如果一个变量V初次读取到的时候是A值,并且准备赋值的时候检查它仍然是A值,那么我们就说他的值没有被其他值改过了吗?如果这段期间它的值曾被改为B,后来又被改回了A,那CAS操作就会误认为它从来没有被改过,这个操作被称为ABA问题


Share

Markdown的一些基本用法

(#)标题对应级别

(#)一级标题

(##)二级标题

(*) 无序列表
  • 列表1
  • 列表2
> 引用

如果你需要引用一小段别处的句子,那么就>要用引用的格式。

引用

插入连接 baidu

[baidu](www.baidu.com

粗体斜体

用两个 * 包含一段文本就是粗体的语法,用一个 * 包含一段文本就是斜体的语法。

表格

表格是我觉得 Markdown 比较累人的地方,例子如下:
| Tables | Are | Cool |

| ------------- |:-------------:| -----:|

| col 3 is | right-aligned | $1600 |

| col 2 is | centered | $12 |

| zebra stripes | are neat | $1 |

分割线

用 ***


代码块

用6个`包括起来

i = 1+1;

你可能感兴趣的:(ARTS 01)