ReentrantLock 可重入锁
ReentrantLock 可以自己控制 tryLock 方法 锁不上的情况
lockInterruptibly 方法 上锁的时候被打断怎么办
ReentrantLock 公平锁和非公平锁,synchronized 只有非公平锁
CountDownLatch
static void countDownLatchTest(){
Thread[] threads = new Thread[100];
CountDownLatch countDownLatch = new CountDownLatch(threads.length);
for (int i = 0; i < threads.length;i++){
threads[i] = new Thread(()->{
int result = 0;
for(int j = 0; j < 10000;j++) result += j;
countDownLatch.countDown(); //原子性 自减
});
}
for(int j = 0; j < threads.length; j++){
threads[i].start();
}
try {
countDownLatch.wait(); //阻塞线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这里的length 是100。
countDownLatch.wait(); 前面的代码都执行,到这行时进行阻塞,和join差不多,阻塞。
阻塞到什么时候 进行后续的代码执行呢,
for(int j = 0; j < 10000;j++) result += j;
countDownLatch.countDown(); //原子性 自减
for循环走完,然后countdown 自减,自减到0的时候,阻塞结束,执行 wait()后续代码。
和join很像
CyclicBarrier
CyclicBarrier barrier = new CyclicBarrier(20,()->{
System.out.println(" ok ");
});
// CyclicBarrier barrier = new CyclicBarrier(20, new Runnable() {
// @Override
// public void run() {
// System.out.println(" 达到20 个了");
// }
// });
for(int i = 0; i < 100; i++){
new Thread(()->{
try {
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
阻塞。阻塞到指定数量时干某件事。如果只对 CyclicBarrier 指定数量而没有传入 run(){} 的实现,则不做任何事。
Phaser
public class MyThread {
static Random r = new Random();
static MyPhaser phaser = new MyPhaser();
static void milliSleep(int mill){
try {
TimeUnit.MICROSECONDS.sleep(mill);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
phaser.bulkRegister(7);
for (int i = 0;i < 5;i++){
final int nameIndex = i;
new Thread(new Person("p" + nameIndex)).start();
}
new Thread(new Person("新郎")).start();
new Thread(new Person("新娘")).start();
}
static class Person implements Runnable{
String name = "";
Person(String name){
this.name = name;
}
void arrive(){
milliSleep(r.nextInt(1000));
System.out.printf(" %s 到达了",name);
System.out.println();
phaser.arriveAndAwaitAdvance();
}
void eat(){
milliSleep(r.nextInt(1000));
System.out.printf("%s 吃饭 ",name);
System.out.println();
phaser.arriveAndAwaitAdvance();
}
void leave(){
milliSleep(r.nextInt(1000));
System.out.printf("%s 离开" , name);
System.out.println();
phaser.arriveAndDeregister();
}
void hug(){
if(name.equals("新郎") || name.equals("新娘")){
milliSleep(r.nextInt(1000));
System.out.printf(" %s 新郎 新娘一起回家",name);
phaser.arriveAndAwaitAdvance();
}else{
System.out.println(name + "回家");
phaser.arriveAndDeregister();
}
}
@Override
public void run() {
arrive();
eat();
leave();
hug();
}
}
static class MyPhaser extends Phaser{
@Override
protected boolean onAdvance(int phase, int registeredParties) {
//phase 设定要进行某个业务逻辑的 指令。
switch (phase){
case 0:
System.out.println(" 婚礼完成");
return false;//返回false,保证可以继续执行后续操作
case 1:
System.out.println(" 吃饭结束 ");
return false;
case 2:
System.out.println(" 参加婚礼的各自回家");
return true;
default:
return true;
}
}
}
}
满足多场景业务使用
onAdvance return false ,则后续逻辑可以进行,不会退出。return true 则执行完毕。
phaser.arriveAndDeregister(); 执行 onAdvance 方法中后续的case。
ReadWriteLock 读写锁、排它锁。
public class MyThread {
static Lock lock = new ReentrantLock();
static int value;
static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
static Lock readLock = readWriteLock.readLock();
static Lock writeLock = readWriteLock.writeLock();
static void read(Lock lock){
lock.lock();
try {
Thread.sleep(1000);
System.out.println(" read over " + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
static void write(Lock lock,int v){
lock.lock();
try {
Thread.sleep(1000);
value = v;
System.out.println(" write over");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
Runnable read = ()->read(lock);
Runnable write = ()->write(lock,new Random().nextInt());
for(int i = 0;i<18;i++) new Thread(read).start();
for(int i = 0;i<2;i++) new Thread(write).start();
}
}
修改下main
Runnable read = ()->read(readLock);
Runnable write = ()->write(writeLock,new Random().nextInt());
效率明显提升。
readlock: 共享锁,读的时候大家都可以读。
writelock:排它锁,写的时候只能一个在写。
写的时候如果不加锁,会造成脏读。读到一半读到了别人刚写到一半的数据。
Semaphore
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(1);
new Thread(()->{
try {
semaphore.acquire();
System.out.println(" T1 running ");
Thread.sleep(200);
System.out.println(" T1 running ");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
semaphore.acquire();
System.out.println(" T2 running ");
Thread.sleep(200);
System.out.println(" T2 running ");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
当 Semaphore semaphore = new Semaphore(1);
当 Semaphore semaphore = new Semaphore(2);
所以 Semaphore 的作用就是,同时允许线程执行的数量。设置1则只能同时一个线程执行,2就是两个,10就是10个。
Exchanger
static Exchanger<String> exchanger = new Exchanger<>();
public static void main(String[] args) {
new Thread(()->{
String s = "T1";
try {
s = exchanger.exchange(s);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + s);
},"t1").start();
new Thread(()->{
String s = "T2";
try {
s = exchanger.exchange(s);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " " + s);
},"t2").start();
}
两个线程之间进行阻塞,然后进行线程数据交换。
三个线程的时候,第三个线程进行阻塞,等待第四个。
所有 Exchanger 是两两交换。先进去的两个线程进行交换。
LockSupport
Thread t = new Thread(()->{
for(int i = 0; i < 10;i++){
System.out.println(i);
if(i == 5){
LockSupport.park();//停止
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" go ");
LockSupport.unpark(t); //继续
LockSupport 暂停或唤醒某个线程。不需要使用synchronized ,不用wait 和 notify。
unpark 可以先于 park 调用,并且有效。 notify 先于 wait 则不行。
ThreadLocal
public class MyThread {
static ThreadLocal<Person> t1 = new ThreadLocal<Person>();
public static void main(String[] args) {
// StampedLock
// CountDownLatch
MyThread m = new MyThread();
new Thread(()->{
try {
TimeUnit.MICROSECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( t1.get());
}).start();
new Thread(()->{
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.set(new Person());
}).start();
}
static class Person{
String name = "zhangsan";
}
按照逻辑,运行应该是 zhangsan ,实际结果 null
set源码
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
出现了一个map,key为线程
就是说,使用 ThreadLocal 的每个线程使用的都是本线程的单独的空间。
ThreadLocal用途: 声明式事务,保证同一个connection
ThreadLocal 用完之后一定要调用 remove() 方法,否则会造成内存泄漏