这里就只浅显的记录一下多线程,不去深究啥对象头、AQS。。。
synchronized
Java关键字synchronized有两种使用方式:①synchronized方法②synchronized块。
1. synchronized方法
synchronized方法就是在方法名前面添加synchronized关键字。
class PrintStr {
synchronized void printA() {}
}
使用这种方式进行同步,锁的是syn方法所在的对象的临界资源。
2. synchronized块
synchronized块是一种比较灵活的方式。使用时需要传入一个对象:
Object o = new Object();
synchronized(o){
o.notify();
o.wait();
}
这个时候锁的就是o这个对象了,notify和wait的用法和ReentrantLock的差不多。看下面。
ReentrantLock
一般来说使用重入锁会用到reentrantLock.lock、reentrantLock.unlock、Condition.await()、Condition.signal()、Condition.signalAll()…
咋用呢?
一般要把ReentrantLock实例化,得到一个重入锁对象 relock。
ReentrantLock relock = new reentrantLock();
刚开始,relock的锁的状态是free的。当有线程1来调用relock.lock()时,会继续往下执行下去,并且获得relock对象的锁。
当线程2来获取锁的时候(调用relock.lock()),是获取不到锁的,线程2或卡在relock.lock();这一行代码。只有当线程1执行relock.unlock()的时候,线程1释放了锁,线程2就会获得锁,并继续执行下去。
当有n个线程来的时候,一个线程释放锁,其余线程谁来获得锁的问题就先暂时不说了(AQS技术)。
下面来讲讲重入锁的精髓 》》Condition《《
(个人理解,谨慎参考)
Condition是用来做线程交替进行的机制。
Condition c = relock.newCondition();
当一个线程在获得锁期间使用了c.await(),这个线程将卡在c.await()这个方法。同时,这个线程将处于一个等待(无锁)的状态。其他的线程可以获得锁(relock.lock())执行代码。只有当另一个线程调用了c.signal()方法时,原先的线程才能醒来,进入“就绪状态”,等待调用了signal的方法执行await()来释放锁,原先的线程获得锁后await()方法才能继续执行下去。
所以signal和signalAll的区别在哪?
假如多个线程都执行了c.await(),某个线程执行了c.signal(),那么排队的线程会有一个能继续执行await()方法往下走。要是执行的c.signalAll(),那么排队线程都能够继续执行await()方法向下走。注意c对象得是同一个。比如c1.signal()只能唤醒c1.await(),不能唤醒c2.await()。
下面来举个栗子:新建两个线程,使他们交替执行,打印出12A 34B 56C …4950 y 5152z
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadNumChar2 {
public static void main(String[] args) throws InterruptedException {
ReentrantLock relock = new ReentrantLock();
Condition c1 = relock.newCondition();
Condition c2 = relock.newCondition();
new Thread(new Runnable() { //数字线程
@Override
public void run() {
try{
relock.lock();
for (int i = 1; i < 53; i++) {
System.out.print(i);
if(i % 2 == 0){
c1.signal(); //使得c1.await()方法能够往下执行
c2.await(); //释放锁,进入睡眠“就绪”状态
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
relock.unlock();
}
}
}).start(); //开启线程
Thread.sleep(2); //使得第二个线程能慢2ms执行,保证数字线程先输出
new Thread(new Runnable() { // 字母线程
@Override
public void run() {
try{
relock.lock();
for (int i = 1; i <= 26; i++) {
System.out.println((char)('A'-1+i));
c2.signal(); // 使c2.await()方法能够向下执行
if(i != 26){
c1.await(); //释放字母线程的锁,进入等待状态
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
relock.unlock();
}
}
}).start(); //开启线程
}
}