• 02.java并发编程之原子性操作


    一、原子性操作

    1、ThreadLocal

     不同线程操作同一个 ThreadLocal 对象执行各种操作而不会影响其他线程里的值

    注意:虽然ThreadLocal很有用,但是它作为一种线程级别的全局变量,如果某些代码依赖它的话,会造成耦合,从而影响了代码的可重用性

    2、变量声明为 final 

    public class FinalDemo {
        private final int finalField;
    
        public FinalDemo(int finalField) {
            this.finalField = finalField;
        }
    }

    3、加锁

    在同步代码块中的代码要尽量的短,不要把不需要同步的代码也加入到同步代码块,在同步代码块中千万不要执行特别耗时或者可能发生阻塞的一些操作,比如I/O操作啥的。

    某个线程在进入某个同步代码块的时候去获取一个锁,在退出该代码块的时候把锁给释放掉

    public class Increment {
        private int i;
    
        private Object lock = new Object();
    
        public void increase(){
            synchronized (lock){
                i++;
            }
        }
    
        public int getI(){
            synchronized (lock){
                return i;
            }
        }
    
        public static void test(int threadNum,int loopTimes){
            Increment increment = new Increment();
    
            Thread[] threads = new Thread[threadNum];
            for(int i = 0; i<threads.length;i++){
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        for(int i = 0; i < loopTimes;i++){
                            increment.increase();
                        }
                    }
                });
                threads[i] = t;
                t.start();
            }
    
            for (Thread t : threads) {  //main线程等待其他线程都执行完成
                try {
                    t.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    
            System.out.println(threadNum + "个线程,循环" + loopTimes + "次结果:" + increment.getI());
        }
    
    
        public static void main(String[] args) {
            test(20, 1);
            test(20, 10);
            test(20, 100);
            test(20, 1000);
            test(20, 10000);
            test(20, 100000);
        }
    }

    二 锁的重入

    只要一个线程持有了某个锁,那么它就可以进入任何被这个锁保护的代码块。

    ublic class SynchronizedDemo {
    
        private Object lock = new Object();
    
        public void m1() {
            synchronized (lock) {
                System.out.println("这是第一个方法");
                m2();
            }
        }
    
        public void m2() {
            synchronized (lock) {
                System.out.println("这是第二个方法");
            }
        }
    
        public static void main(String[] args) {
            SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
            synchronizedDemo.m1();
        }
    }

    三、同步方法

    public class Increment {
    
        private int i;
    
        public void increase() {
            synchronized (this) {   //使用this作为锁
                i++;
            }
        }
    
        public static void anotherStaticMethod() {
            synchronized (Increment.class) {   //使用Class对象作为锁
                // 此处填写需要同步的代码块
            }
        }
    }

    可以简写成:

    public class Increment {
    
        private int i;
    
        public synchronized increase() {   //使用this作为锁
            i++;
        }
    
        public synchronized static void anotherStaticMethod() {   //使用Class对象作为锁
            // 此处填写需要同步的代码块
        }
    }
  • 相关阅读:
    ZeptoLab Code Rush 2015
    UVa 10048 Audiophobia【Floyd】
    POJ 1847 Tram【Floyd】
    UVa 247 Calling Circles【传递闭包】
    UVa 1395 Slim Span【最小生成树】
    HDU 4006 The kth great number【优先队列】
    UVa 674 Coin Change【记忆化搜索】
    UVa 10285 Longest Run on a Snowboard【记忆化搜索】
    【NOIP2016提高A组模拟9.28】求导
    【NOIP2012模拟10.9】电费结算
  • 原文地址:https://www.cnblogs.com/wjh123/p/9000257.html
Copyright © 2020-2023  润新知