zoukankan      html  css  js  c++  java
  • 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对象作为锁
            // 此处填写需要同步的代码块
        }
    }
  • 相关阅读:
    函数对象、名称空间与作用域
    函数
    leetcode语法练习(二)
    leetcode语法练习(一)
    字符编码与文件操作
    集合类型内置方法与总结
    列表,元组与字典类型
    数据类型内置方法之数据类型与字符串类型
    [SVG实战]饼图全面解析
    [JavaScript语法学习]重新认识JavaScript
  • 原文地址:https://www.cnblogs.com/wjh123/p/9000257.html
Copyright © 2011-2022 走看看