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 。

 

posted @ 2019-05-05 20:46  李鹏飞ONLINE  阅读(148)  评论(0编辑  收藏  举报