线程基础
三种启动方式:
- 实现Thread类,然后new 一个对象,调用start方法
- 实现Runable、接口,然后new Thread(new Runable()).start(),同理可用lambd表达式表示
- 线程池Executors
public class StartThread { static class Thread1 extends Thread{ @Override public void run() { System.out.println("thread 1 run"); } } static class Thread2 implements Runnable{ @Override public void run() { System.out.println("thread 2 run"); } } public static void main(String[] args) throws InterruptedException { new Thread1().start(); new Thread(new Thread2()).start(); new Thread(() -> { System.out.println("thread 3 run"); }).start(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(()->{ System.out.println("thread 4 run"); }); Thread.sleep(1000); System.out.println("end"); } }
三个方法
- Thread.sleep() 睡眠
- Thread.yeild() 当前线程进入等待队列
- otherThread.join() 调用其他线程,等其他线程执行完了,再执行自己
七个状态
- new 创建状态
- ready 调用start之后的状态
- running 执行状态
- timedwaiting 时间等待,调用sleep(time),wait(time),join(time).时间结束进入执行状态
- waiting 等待状态,调用wait(),join(),需要被唤醒才能进入执行状态
- blocked 阻塞状态,同步锁并且等待锁的时候
- teminated 结束
synchronized
4个状态:
- 无锁
- 偏向锁
- 轻量锁
- 重量锁
底层是sync,锁升级的概念
可重入锁:当同一个线程,可以再次拿同一把锁
程序中出现异常,默认情况下锁会被释放
双重检查锁有没有必要volatile
有必要!在初始化对象的时候,分为三步:1.在内存中申请空间,并初始化值。2.将真正的值,放入内存空间中。3.将对象指向该内存地址。
如果没有volatile,那么第二步和第三步顺序可能会颠倒。在一个线程中,先执行了第三步,另外一个线程就会看到实例已经有值了,那么就不会在进入锁的代码,而是直接用该值。
一般情况下不会出现该问题,只有在超高并发情况下才可能有问题
ReentrantLock
底层是CAS
Lock lock = new ReentrantLock()
lock.lock();
lock.unlock();
boolean lockFlag = lock.tryLock(5, sencends);
//公平锁.之后进行加锁的线程,将会按顺序排队,先排队的先得到锁
lock = new RentrantLock(true);
lock.newCondition()可以创建一个新的等待队列。然后可以控制只唤醒指定队列的线程
private ReentrantLock lock = new ReentrantLock();
private Condition consumer = lock.newCondition();
private Condition provider = lock.newCondition();
provider.signalAll();
CountdownLatch
public static void main(String[] args) throws InterruptedException {
CountDownLatch cd = new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
new Thread(()->{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cd.countDown();
}).start();
}
cd.await();
System.out.println("end");
}
CyclicBarrier
满足多少个cyclicBarrier后,开始执行
// 创建方式
CyclicBarrier cyc = new CyclicBarrier(20);
// 带action的创建方式
CyclicBarrier cyc = new CyclicBarrier(20, ()->{
System.out.println("足够20个啦");
});
Phase
按阶段执行。
当注册的线程,达到每一个阶段时,都停止并等待/停止并取消注册。等所有线程都到达该阶段时,等待的线程一起执行下一阶段
public class PhaseThread {
public static void main(String[] args) {
Phaser phaser = new Phaser(){
protected boolean onAdvance(int phase, int parties) {
switch (phase){
case 0:
System.out.println("第一阶段,线程数量 " + parties );
return false;
case 1:
System.out.println("第二阶段,线程数量 " + parties);
return false;
}
return false;
}
};
phaser.bulkRegister(7);
phaser.arriveAndAwaitAdvance(); //到达并等待
phaser.arriveAndDeregister(); // 到达并取消注册
}
}
ReadWriteLock
读锁是共享锁,写锁是排他锁
读锁可以同时并发读,写锁只能一个个写
public class ReadWriteLockThread {
static ReadWriteLock lock = new ReentrantReadWriteLock();
static Lock readLock = lock.readLock();
static Lock writeLock = lock.writeLock();
public static void main(String[] args) {
for (int i = 0; i < 18; i++) {
new Thread(() -> {
try {
readLock.lock();
System.out.println("read------");
ThreadUtils.sleep(1000);
} finally {
readLock.unlock();
}
}).start();
}
for (int i = 0; i < 2; i++) {
new Thread(() -> {
try {
writeLock.lock();
System.out.println("write------");
ThreadUtils.sleep(1000);
} finally {
writeLock.unlock();
}
}).start();
}
}
}
Semaphore
最多允许多少线程同时执行
public class SemaphoreThread {
public static void main(String[] args) {
Semaphore s = new Semaphore(3);
for (int i = 0; i < 18; i++) {
new Thread(() -> {
try {
s.acquire();
System.out.println("thread start");
ThreadUtils.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
s.release();
}
}).start();
}
}
}
LockSupport
让线程停住,然后其他地方来让线程继续
public class LockSupportThread {
public static void main(String[] args) {
Thread t = new Thread(()->{
for (int i = 0; i < 10; i++) {
if(i == 5){
LockSupport.park();
}
System.out.println(i);
ThreadUtils.sleep(1000);
}
});
t.start();
// 1.在park之前执行unpark
LockSupport.unpark(t);
//2.在park之后执行unpark
// ThreadUtils.sleep(8000);
// System.out.println("8秒之后");
// LockSupport.unpark(t);
}
}
需要注意的是,unpark可以在park之前执行!并且起效果