java线程(三)

1.线程同步

每个用synchronized关键字声明的方法都是临界区。在java中,同一个对象的临界区,在同一时间只有一个允许被访问。线程同步一共有七种方式。

1.1同步方法

使用synchronized关键字修饰的方法

注意:synchronized关键字也可以修饰静态方法,如果调用该静态方法,将会锁住整个类

代码如下:

public synchronized void save(){}

1.2同步代码块

用synchronized关键字修饰的语句块。

被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。

代码如下:

synchronized(object){}

注意:被锁住的代码块,每个线程进入的时候,只有将该代码块执行结束之后,才会执行下一个线程。同步是一种高开销的操作,因此应该尽量减少同步的内容,通常没有必要同步整个方法,只要使用synchronized同步关键代码块即可。

1.3使用特殊域变量(volatile)

    a.volatile关键字为域变量的访问提供了一种免锁机制, 
    b.使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新, 
    c.因此每次使用该域就要重新计算,而不是使用寄存器中的值 
    d.volatile不会提供任何原子操作,它也不能用来修饰final类型的变量 实现线程同步

1.4 使用重入锁实现线程同步

    在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。 
    ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 
    它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力


    ReenreantLock类的常用方法有:

        ReentrantLock() : 创建一个ReentrantLock实例 
        lock() : 获得锁 
        unlock() : 释放锁 

例如:

 public void save(int money) {

                Lock lock = new ReentrantLock();
                lock.lock();
                try{
                    account += money;
                }finally{
                    lock.unlock();
                }
                
            }

相当于

 public synchronized void save(int money) { account += money; }

 1.5使用局部变量实现线程同步

  如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 
    副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

    ThreadLocal 类的常用方法:

    ThreadLocal() : 创建一个线程本地变量 
    get() : 返回此线程局部变量的当前线程副本中的值 
    initialValue() : 返回此线程局部变量的当前线程的"初始值" 
    set(T value) : 将此线程局部变量的当前线程副本中的值设置为value

public class Bank{
            //使用ThreadLocal类管理共享变量account
            private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){
                @Override
                protected Integer initialValue(){
                    return 100;
                }
            };
            public void save(int money){
                account.set(account.get()+money);
            }
            public int getAccount(){
                return account.get();
            }
        }

1.6使用阻塞队列实现线程同步

    使用javaSE5.0版本中新增的java.util.concurrent包将有助于简化开发。 
    本小节主要是使用LinkedBlockingQueue<E>来实现线程的同步 
    LinkedBlockingQueue<E>是一个基于已连接节点的,范围任意的blocking queue。 

   LinkedBlockingQueue 类常用方法 
    LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue 
    put(E e) : 在队尾添加一个元素,如果队列满则阻塞 
    size() : 返回队列中的元素个数 
    take() : 移除并返回队头元素,如果队列空则阻塞 

1.7使用原子变量实现线程同步

 

需要使用线程同步的根本原因在于对普通变量的操作不是原子的。


那么什么是原子操作呢?
原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作
即-这几种行为要么同时完成,要么都不完成。

在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类
使用该类可以简化线程同步。

其中AtomicInteger 表可以用原子方式更新int的值,可用在应用程序中(如以原子方式增加的计数器),
但不能用于替换Integer;可扩展Number,允许那些处理机遇数字类的工具和实用工具进行统一访问。

AtomicInteger类常用方法:
AtomicInteger(int initialValue) : 创建具有给定初始值的新的AtomicInteger
addAddGet(int dalta) : 以原子方式将给定值与当前值相加
get() : 获取当前值

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值