线程同步

同步方法

    仅当前执行线程能访问被synchronized的方法,若其他线程尝试访问此被synchronized修饰的方法,被挂起直到第一个线程该方法的调用完成(因为都竞争对象锁,谁先获得,谁先执行synchronized方法)。静态方法有不同的行为,只有一个执行线程能访问被synchronized修饰的静态方法,但是其他线程能访问该对象的非静态方法。

public synchronized void inc() {
        try {
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        count++;        
}
synchronized (this) {//代码块
      // Java code
}

在同步类中分配独立属性

public class ThreadTest {
    private long shareData = 100;
    private long shareData1 = 100;//shareData shareData1是独立的两个共享变量
    private Object lock1 = new Object();//shareData的锁
    private Object lock2 = new Object();//shareData1的锁
    
    public void addData1() {
        synchronized (lock1) {
            shareData++;
        }
    }
    public void addData2() {
        synchronized (lock2) {
            shareData1++;
        }
    }
}

在同步代码中使用条件

    Java的Object对象实现了wait(),notify(),notifyAll()方法,一个线程可以在synchronized代码块内调用wait方法,若在之外调用,JVM会抛出IllegalMonitorStateException异常。当线程调用wait()方法时,JVM将线程进入sleep状态,释放object的锁对象,允许其他线程来执行synchronized代码块。在受保护代码块内使用notify()或notifyAll()来唤醒等待该object锁的线程。
public synchronized void set(){
      while (storage.size()==maxSize){
        try {
          wait();//继续等待
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      storage.offer(new Date());
      System.out.printf("Set: %d",storage.size());
      notifyAll();//唤醒其他等待此对象锁的线程
}

使用Lock同步代码块

    相比synchronized代码块,Lock接口提供了额外的特性。
     tryLock():尝试获取锁的控制,如果不能获得锁的控制,立即返回,不会将线程置入sleep状态,该方法返回boolean值,表明是否获得锁。
     lock()方法:获取锁,若不能获得,被置入sleep状态,一直等待。
private final Lock queueLock=new ReentrantLock();
public void printJob(Object document){
    queueLock.lock();
    try {
      Long duration=(long)(Math.random()*10000);
      System.out.println(Thread.currentThread().getName()+ ": 
PrintQueue: Printing a Job during "+(duration/1000)+ 
" seconds");
      Thread.sleep(duration);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }finally {
      queueLock.unlock();
    }  
}    
    使用lock时,注意避免死锁,典型的情况:thread A持有x,thread B持有y,此时线程A想要持有y,而线程B想要持有x,就出现死锁现象了。

使用读写锁同步数据访问

    线程性能一个显著提升是ReadWriteLock接口的实现ReentrantReadWriteLock,它有两个锁,一个读锁,另一个是些锁。可以有多个线程同时使用读操作,但仅有一个线程使用写操作。当一个线程进行写操作,不能存在任何线程进行读操作。
private ReadWriteLock lock = new ReentrantReadWriteLock();

public double getPrice1() {
    lock.readLock().lock();
    double value=price1;
    lock.readLock().unlock();
    return value;
}

public double getPrice2() {
    lock.readLock().lock();
    double value=price2;
    lock.readLock().unlock();
    return value;
}

public void setPrices(double price1, double price2) {
    lock.writeLock().lock();
    this.price1=price1;
    this.price2=price2;
    lock.writeLock().unlock();
}

修改锁公平性

    ReentrantLock和ReentrantReadWriteLock类提供一个boolean参数fair,允许用户控制它的行为,false是默认值,成为非公平模式(当有两个线程等待一个lock,lock必须选择其中一个来访问,选择时没有任何规则。为true时,称为公平模式(有多个线程等待这个锁时,lock选择等待时间最长的线程执行,lock()和unlock受此特性影响,单tryLock()傻等,所以不受此特性影响)。
Lock queueLock=new ReentrantLock(true);//公平锁

使用锁的多个条件

    一个lock会与一个或多个条件关联,这些条件以Condition接口声明,提供了挂起线程和唤醒挂起线程的机制。
ReentrantLock lock = new ReentrantLock();
Condition lines = lock.newCondition();
Condition space = lock.newCondition();//lines和space配对使用
public void insert(String line) {
    lock.lock();
    try {
      while (buffer.size() == maxSize) {//缓冲区已满
        space.await();
      }
      buffer.offer(line);
      System.out.printf("%s: Inserted Line: %d\n", Thread.
currentThread().getName(),buffer.size());
      lines.signalAll();//已添加
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
}
public String get() {
    String line=null;
    lock.lock();    
    try {
      while ((buffer.size() == 0) &&(hasPendingLines())) {
        lines.await();//缓冲区为空
      }
      
      if (hasPendingLines()) {
        line = buffer.poll();
        System.out.printf("%s: Line Readed: %d\n",Thread.
currentThread().getName(),buffer.size());
        space.signalAll();//已取走
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
    return line;
}






    
    



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值