zoukankan      html  css  js  c++  java
  • 并发编程学习(一)

    基本概念:

    synchronized上加static和不加的区别就是有static是类锁,不加就是对象锁。

    线程安全:当多个线程访问某一个类(对象或方法)时,这个类始终能表现出正确的行为,那么这个类就是一个线程安全的。

    synchronized:可以在任何对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"。

    线程安全:

    public class MyThread extends Thread{
        private int count = 5;
    
        public  void run(){
            count--;
            System.out.println(this.currentThread().getName()+" count = "+count);
        }
    
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            Thread t1 = new Thread(myThread,"t1");
            Thread t2 = new Thread(myThread,"t2");
            Thread t3 = new Thread(myThread,"t3");
            Thread t4 = new Thread(myThread,"t4");
            Thread t5 = new Thread(myThread,"t5");
    
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
        }
    }
    输出结果:
    t1 count = 4
    t4 count = 2
    t3 count = 1
    t2 count = 3
    t5 count = 0

    可以看出并没有按照我们程序的顺序调用,要实现线程安全那就要加synchronized;

       public  synchronized void run(){
            count--;
            System.out.println(this.currentThread().getName()+" count = "+count);
        }

     有时候我们会调用同一对象内的两个方法,一个加锁,一个未加锁,未加锁的不会受加锁的影响。

    以下程序会出现脏读:

    public class MyObject {
        private String name = "test";
        private String pwd = "123";
    
        public synchronized void setValue(String name,String pwd){
            this.name = name;
    
            try{
                Thread.sleep(2000);//睡眠2秒,但name值已经设置过了
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            this.pwd = pwd;
    
            System.out.println("set结果name="+name+",pwd="+pwd);
        }
    
        public void getValue(){
            System.out.println("get结果name="+name+",pwd="+pwd);
        }
    
        public static void main(String[] args) throws InterruptedException {
            MyObject myObject = new MyObject();//同一对象
            Thread t1 = new Thread(new Runnable() {//主线程
                @Override
                public void run() {
                    myObject.setValue("wt","456");
                }
            });
    
            t1.start();//调set方法
            Thread.sleep(1000);//休眠一秒调get方法
    
            myObject.getValue();
        }
    }
    执行结果:
    get结果name=wt,pwd=123
    set结果name=wt,pwd=456
    原因:调set方法时休眠了两秒,但name值已经设置过了,get方法没加锁,所以取出来是只设置name的值。
    public synchronized void getValue(){//get方法加锁输出结果就不会出现脏读
    System.out.println("get结果name="+name+",pwd="+pwd);
    }


    Volatile关键字:

       作用:就是强制线程到主内存里去读取变量,而不去线程工作内存区里去读取,从而实现了多个线程间的变量可见,也就是满足线程安全的可见性。

      线程可以执行的操作有use(使用)、assign赋值、load装载、store存储、锁定、解锁。

      主内存的操作有:read,write,lock,unlock每个操作都是原子性的。

     volatile一般用于只针对多个线程可见的变量操作,并不能代替synchronzied的同步功能,它不具有原子性,要实现原子 性建议使用atomic类的系统对象,

    public class RunThread extends Thread {
        private boolean isRunning = true;
        private void setRunning(boolean isRunning){
            this.isRunning = isRunning;
        }
    
        public void run(){
            System.out.println("进入run方法");
            while (isRunning == true){
              // System.out.println("这个很耗时,打开可能会取到isRunning");
            }
            System.out.println("线程停止");
        }
    
        public static void main(String[] args) throws InterruptedException {
            RunThread rt = new RunThread();
            rt.start();
    
            Thread.sleep(3000);
    
            rt.setRunning(false);
            System.out.println("isrunning设置为false");
            Thread.sleep(1000);
    
            System.out.println("isRunning:"+rt.isRunning);
        }
    }
    输出结果:
    进入run方法
    isrunning设置为false
    isRunning:false


    程序仍然处于运行中
    加入volatile后:private volatile boolean isRunning = true;
    执行结果:
    进入run方法
    isrunning设置为false
    线程停止
    isRunning:false

    出现上面的结果是因为,每个线程都有自己的一个内存区域(这样运行更快),在程序运行时,把需要的数据装载到自己的工作内存,而主内存中的数据仍然存在,我们上面程序修改isRunning为false,只是修改了主内存中的数据,线程的工作内存并没有修改,所以会出现主程序走完了,线程还在执行。

    当isRunning被volatile修饰时,变量改变时会强制线程执行引擎去主内存中读取。

    ...
  • 相关阅读:
    php在没用xdebug等调试工具的情况下如何让调试内容优雅地展现出来?--php数组格式化
    linux自动定时备份web程序和mysql数据库
    linux下用cronolog分割apache日志
    写在前面--点燃酱爆心中的那团火
    我对知乎前端相关问题的十问十答(转)
    参考美团、饿了么 && localStorage
    vue-scroller的使用 && 开发自己的 scroll 插件
    如何发布一个包到npm && 如何使用自己发布的npm包 && 如何更新发布到npm的package && 如何更新当前项目的包?
    VUE中toast的使用与开发
    如何在vue && webpack 项目中的单文件组件中引入css
  • 原文地址:https://www.cnblogs.com/javage/p/9496546.html
Copyright © 2011-2022 走看看