zoukankan      html  css  js  c++  java
  • JAVA 多线程(5)

    锁对象的改变:

    关于锁,如果多个线程争的是一个锁,那么就是同步的,如果不是一个锁就是异步的。

    那么关键点就在于是不是同一个锁,如果在运行过程中锁改变了,那么变成异步的话就会出现问题,需注意。

    volatile 关键字:

    在多个线程中可见,不具备原子性。

    线程中的实例属性在 -server 模式中,线程会一直在私有堆栈中取得,但是如果我们在主线程中更新了这个标识位,那么只是更新了公共堆栈。

    所以为了解决这个问题,volatile关键字修饰的属性会强制从公共堆栈中取值。

    如下:

    static class MyThread extends Thread{
            private volatile boolean isRun = false;
    
            public void setRun (boolean run){
                isRun = run;
            }
            @Override
            public void run() {
                System.out.println("begin");
                while (!isRun){
                    System.out.println(Thread.currentThread().getName());
                }
                System.out.println("end");
            }
        }
    
        public static void main(String[] args){
            Thread t = new MyThread();
            t.start();
            try {
                Thread.sleep(1);
                ((MyThread) t).setRun(true);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    输出:

    注意(与synchronized 比较):

    1.volatile 性能更好,但只能修饰属性变量

    2.多线程访问volatile 不会发生阻塞

    3.能保证可见性,但不能保证原子性

    关于i++

    它是非线程安全的,操作步骤:

    1.从内存中取出i值

    2.计算i的值

    3.写入到内存

    但是并不是同步的。

    如:

     private static volatile int i = 0;
    
        public static void main(String[] args){
            Runnable run = new Runnable() {
                @Override
                public void run() {
                    for (int j = 0;j < 10; j++) {
                       i ++;
                       System.out.println(Thread.currentThread().getName()+":: "+i);
                    }
                }
            };
    
            Thread t = new Thread(run);
            Thread t2 = new Thread(run);
            t.start();
            t2.start();
        }

    输出:

    从输出结果可以看出,由于不是同步操作,所以线程1和线程2乱序输出,线程1和线程2同时刚开始同时输出了2(这个例子中)。

    加上synchronized

    public void run() {
                    for (int j = 0; j < 10; j++) {
                        synchronized (this) {
                            i++;
                            System.out.println(Thread.currentThread().getName() + ":: " + i);
                        }
                    }
                }

    输出:

     

    第二种方式:使用原子类

    private static AtomicInteger i = new AtomicInteger(0);

    但原子类也有可能出现乱序。

    如果在方法中使用了原子类,但是由于方法并不是同步的,所有有可能会先执行后面的方法。

    遇到这样的情况,那就加上synchronized 。

    成灰之前,抓紧时间做点事!!
  • 相关阅读:
    C#实体类对象修改日志记录
    C#中关于增强类功能的几种方式
    Elasticsearch入坑指南之RESTful API
    React入门实例
    .Net Core+Vue.js+ElementUI 实现前后端分离
    ElasticSearch入坑指南之概述及安装
    MySQL优化技巧
    RabbitMQ入门教程——路由(Routing)
    RabbitMQ入门教程——发布/订阅
    RabbitMQ入门教程——工作队列
  • 原文地址:https://www.cnblogs.com/jony-it/p/10816165.html
Copyright © 2011-2022 走看看