await方法会一直阻塞;之后会释放所有等待线程,await的所有后续调用都将返回;CountDownLatch(int count);//构造用给定计数初始化的同步计数器;
void await();//使当前线程在计数器至0前一直等待,除非被中断;
boolean await(long timeout,TimeUnit unit);//使当前线程在计数器倒计数至0前一直等待,除非被中断或超时
void countDown();//计数器减一,如果到达0,则释放所有等待的线程;
long getCount();//返回当前计数;
public class CountDownLatchDemo {
static class Worker extends Thread{
private String workerName;
private CountDownLatch latch;
public Worker(String workerName,CountDownLatch latch){
this.workerName = workerName;
this.latch = latch;
}
@Override
public void run() {
try {
System.out.println("Thread "+ this.workerName+" is begin!");
Thread.sleep(2000l);
System.out.println("Thread "+ this.workerName+" is end!");
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
latch.countDown();
}
}
}
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
Worker worker1 = new Worker("11111",latch);
Worker worker2 = new Worker("22222",latch);
Worker worker3 = new Worker("33333",latch);
worker1.start();
worker2.start();
worker3.start();
latch.await();
System.out.println("main end");
}
}
//运行结果:
Thread 11111 is begin!
Thread 33333 is begin!
Thread 22222 is begin!
Thread 11111 is end!
Thread 22222 is end!
Thread 33333 is end!
main end
barrier在释放等待线程中可以重用,所以叫做循环的barrier;CyclicBarrier(int parties);//创建一个新的循环屏障,它将在给定数量的线程处于等待状态在启动,但不会在启动barrier时进行预定义的操作;
CyclicBarrier(int parties,Runable barrierAction);//创建一个新的循环屏障,它将在给定数量的线程处于等待状态在启动,并在启动barrier时执行给定的屏障操作barrierAction,该操作有最后一个进入barrier的线程执行;
int await();//在所有参与者都已经在此barrier上调用await方法之前,将一直等到;
int await(long timeout,TimeUnit unit);//在所有参与者都已经在此屏障上调用await方法之前将一直等待,或者超出了指定的等待时间;
int getNumberWaiting();//返回当前在平长出等待的线程数目;
int getParties();//返回要求启动此barrier的线程数目;
void reset();//将循环屏障重置为初始章台;
public class CyclicBarrierDemo {
static class Worker extends Thread{
private String workerName;
private CyclicBarrier barrier;
public Worker(String workerName,CyclicBarrier barrier){
this.workerName = workerName;
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println("Thread "+ this.workerName+" is begin!");
Thread.sleep(2000l);
System.out.println("Thread "+ this.workerName+" is end!");
barrier.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
}
}
static class TotalTask extends Thread{
@Override
public void run() {
System.out.println("所有线程都到达barrier");
}
}
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3,new TotalTask());
Worker worker1 = new Worker("11111",barrier);
Worker worker2 = new Worker("22222",barrier);
Worker worker3 = new Worker("33333",barrier);
worker1.start();
worker2.start();
worker3.start();
System.out.println("main end");
}
}
//运行结果:
main end
Thread 11111 is begin!
Thread 33333 is begin!
Thread 22222 is begin!
Thread 11111 is end!
Thread 33333 is end!
Thread 22222 is end!
所有线程都到达barrier
CountDownLatch:一个线程等待另外N个线程完成某个事情之后继续执行,重点是一个线程等待;CyclicBarrier:N个线程互相等待,任何一个线程完成之前,所有线程都必须等待;acquire,等待获取许可;release()释放当前占用的许可,允许其他阻塞的线程获得;Semaphore(int permits);//创建具有给定许可数目、非公平的Semphore对象;
Semaphore(int permits,boolean fair);//创建具有给定许可数目、公平的semphore对象,所谓公平性就是先来先服务FIFO;
void acquire();//从信号量获取一个许可,在获取到许可之前线程将被阻塞;
int acailablePermits();//返回此信号量中的可用许可数目
void release();//释放当前许可
public class SemaphoreDemo {
static class Worker extends Thread{
private String workerName;
private Semaphore semaphore;
public Worker(String workerName,Semaphore semaphore){
this.workerName = workerName;
this.semaphore = semaphore;
}
@Override
public void run() {
try {
Thread.sleep(1000l);
semaphore.acquire();
System.out.println("Thread "+ this.workerName+" 获取许可!");
Thread.sleep(2000l);
semaphore.release();
System.out.println("Thread "+ this.workerName+" 释放许可");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 0; i < 12; i++) {
Worker worker = new Worker("worker"+i, semaphore);
worker.start();
}
System.out.println("main thread end");
}
}
//运行结果:
main thread end
Thread worker10 获取许可!
Thread worker11 获取许可!
Thread worker7 获取许可!
Thread worker10 释放许可
Thread worker2 获取许可!
Thread worker3 获取许可!
Thread worker0 获取许可!
Thread worker11 释放许可
Thread worker7 释放许可
Thread worker3 释放许可
Thread worker0 释放许可
Thread worker2 释放许可
Thread worker6 获取许可!
Thread worker1 获取许可!
Thread worker9 获取许可!
Thread worker6 释放许可
Thread worker8 获取许可!
Thread worker4 获取许可!
Thread worker5 获取许可!
Thread worker9 释放许可
Thread worker1 释放许可
Thread worker4 释放许可
Thread worker5 释放许可
Thread worker8 释放许可
线程唯一标识,自动生成,不允许修改;
线程初始化方法init() 会给线程设置id,该id通过synchronized标记的 nextThreadID()方法获取,id自增;
线程的名称,可以自定义成具有具体含义的名字,便于识别不同作用的线程,可重复;
如果没有指定线程的名称,默认是“Thread-”+nextThreadNum();
true:守护线程,false:用户线程;start() 之前设置这个属性,线程运行中设置线程守护属性会抛出异常;
新创建一个线程对象,但还没有调用start()方法;
Java线程中将就绪(ready)和运行中(running)两种笼统的称为运行,线程创建后,其他线程调用了该对象的start()方法,该状态位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready),就绪状态的线程在获得CPU时间片变为运行中状态(running);
表示线程阻塞于锁;
进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断);
该状态不同于等待,它可以在指定的时间后自行返回;
表示该线程已经执行完毕;
notify/notifyAll唤醒后,回进入同步队列竞争锁,如果获得锁,进入RUNNANBLE状态,否则进入BLOCKED状态等待获取锁;Thread.sleep(long millis);//一定是当前线程调用此方法,当前线程进入TIMED_WAITING状态,但不释放锁,millis后线程自动苏醒进入就绪状态,作用:给其他线程执行机会的最佳方式;
Thread.yield();//一定是当前线程调用此方法,当前线程放弃获取CPU时间片,但不释放锁资源,有运行状态变为就绪状态,让OS再次选择线程,作用:让相同优先级的线程轮流执行,但不保证一定会轮流执行,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中,Thread.yield()不会导致阻塞,该方法于sleep类似,只是不能有用户指定暂停多长时间;
thread.join()/thread.join(long millis);//当前线程里调用其他线程t 的join方法,当前线程进入WAITING/TIMED_WAITING状态,当前线程不会释放已经持有的对象锁,线程 t 执行完毕或者millis时间到,当前线程一般情况下进入RUNNABLE状态,也有可能进入BLOCKED状态;
obj.wait();//当前线程调用对象的wait()方法,当前对象释放锁,进入等待队列,依靠notify()/notifyAll()唤醒,或设置过期时间唤醒;
obj.notify();//唤醒在对象监视器上等待的单个线程,选择是任意性的;
LockSupport.park()/LockSupport.parkNanos(long nanos),LockSupport.partUntil(long deadlines);//当前线程进入WAITING/TIMED_WAITING状态,对比wait方法,不需要获取锁就能让线程进入WAITING/TIMED_WAITING状态,需要通过LockSupport.unpark(Thread thread)唤醒;
当多个线程可以一起工作去解决某个问题时,如果某些部分必须在其他部分之前完成,那么就需要对线程进行协调;
后台线程:
daemon)线程,是指在程序运行的时候在后台提供的一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非后台线程结束时,程序也就终止了,同时会kill掉进程中所有的后台线程。setDaemon()方法,才能将线程设置为后台线程。finally子句并不会执行,原因在于当最后一个非后台线程终止时,后台程序会突然终止,JVM会立即关闭所有后台进程并且是以一种粗暴的形式进行关闭。Executor通常是一种更好的方式,因为Executor控制的所有任务可以同时被关闭,并且关闭是有序的。直接继承Thread实现线程:
在非常简单的情况下,可以直接从Thread继承的方式来实现线程。
事实上,实现接口的方式会更好一些,原因在于:
Java不支持多重继承,因此继承了Thread类就无法继承其他类,但可以实现多个接口;
类可能只要求执行就行,继承整个Thread类开销过大。
加入一个线程:
join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复。join()时带上一个超时参数,这样如果目标线程在这段时间到期时还没有结束的话,join()方法总能返回。join()方法的调用可以被中断,做法是在调用线程上调用interrupt()方法,这时需要用到try-catch子句。wait()使得线程等待某个条件满足,线程在等待时被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用notify()或者notifyAll()来唤醒挂起的线程;wait()、notify()、notifyAll()都是属于Object的一部分,而不是属于Thread,并且只能用在同步方法或同步控制快中,否则在运行时会抛出异常;wait()挂起期间,线程会释放锁,如果不释放锁,那么其他线程就无法进入对象的同步方法或同步控制块中,也就无法执行notify()、notifyAll()来唤醒挂起的线程,造成死锁;wait()和sleep()的区别:
wait()是Object的方法,sleep()是Thread的静态方法;wait()会释放锁,sleep()不会;join()是通过wait()实现的,因此join()也能释放锁;notify() 和 notifyAll()的区别:
对于多个任务的单个对象处于
wait()状态,调用notifyAll()方法比调用notify() 方法更安全,notify() 方法在众多等待同同一个锁的任务只有一个会被唤醒,因此除非能够保证被唤醒的任务是恰当的任务,否则线程调度的非确定性,可能会导致死锁,而notifyAll()则是唤醒所有等待同一个锁的所有任务;(事实上notifyAll() 真正唤醒的是等待该条件的任务,而不是所有任务 )
可以在Condition上调用await()方法使线程等待,其他线程调用signal()或signalAll()方法唤醒等待的线程,await()可以指定等待的条件;
两个或两个以上的进程因为争夺资源造成的一种等待的过程就是死锁,如果没有外力干涉,就不可能再进行下去;
使用jps和jstack命令:

Concurrent开头的集合类,可以支持多个线程并发写入访问,写入操作都是线程安全的,读取操作不必锁定,采用更复杂的算法,保证永不会锁住整个集合,因此在并发写入的时候有较好的性能;ConcurrentLinkedQueue实现多线程高效、无需等待的访问,不能使用null元素;ConcurrentLinkedQueue和ConcurrentLinkedHashMap最好不要使用迭代器,因为迭代器可能不能反映出创建迭代器后所做的修改,但程序不会报出异常;CopyOnWrite开头的集合类,采用复制底层数组的方式来实现写操作,读时无需加锁,对复制的新数组进行写操作,所以线程安全频繁的复制数组,性能不交叉,但是读操作没有加锁和阻塞就很快、很安全;