------------恢复内容开始------------
1.什么是线程?线程(Thread):字面意思是线路,即应用程序(进程)中程序执行的线路。JAVA虚拟机允许一个应用程序中,可以同时并发存在多条程序执行线路。每个线程都有一个优先级属性,优先级高的线程,可能会被CPU优先执行。换言之,线程是应用程序(进程)在运行过程中,通过操作系统想CPU发起的一个任务,这个任务只能访问当前进程的内存资源。
1.1 线程状态
线程状态:即线程对象再不同的运行时期存在这不同的状态,在Thread类中通过一个内部枚举类State保存状态信息。
点击查看代码public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
可通过Thread.getState()获取当前线程的状态:
点击查看代码/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}
1.2JAVA线程状态转换
1.4 sleep()与yield()
- 线程休眠sleep()
Thread类的sleep()方法,使当前正在执行的线程以指定的毫秒数暂时停止执行,具体停止时间取决于系统定时器和调度程序的精度和准确性。当前线程状态由RUNNABLE切换到TIME_WAITING。sleep方法不会使线程丢失任何监视器,因此当前线程仍然占用CUP分片。
- 线程让步yield()
yield()方法对线程调度器发出一个暗示,即当前线程愿意让出正在是用的处理器。调度程序可以响应暗示的请求,也可以自由的忽略这个提示。
注意:yield()方法仅仅是一个暗示,没有任何机制保证它一定会采纳。关于线程调度器,它是Java线程机制的底层对象,可以把CPU的使用权从一个线程转移到另一个线程。如果你的计算机是多核处理器,如何分配线程得到不同的处理器执行任务,都需要依赖线程调度器。
1.6守护者线程
- 概念:JAVA线程中有两种线程,一种是用户线程,另一中是守护线程(Daemon)。
所谓守护线程,是指在程序运行的时候在后台提供一种通用的服务线程,比如垃圾回收线程就是一个很称职的守护者(当一个对象不再被引用的时候,内存回收它占领的空间,以便被后来的新对象使用)。
Daemon线程与用户线程在使用时没有任何区别,唯一不同的是:当所有用户线程结束是时,程序也会终止,Java虚拟机不管是否存在守护者线程都会推出。
Thread.setDaemon()方法可将用户线程标记为守护者,调用isDaemon()方法可以判断线程是否是一个守护者。
2. 线程安全与共享资源竞争线程安全问题:多个线程同时访问同一个对象的某个方法时,如果该方法中存在对共享资源的操作,则可能引发线程安全问题。典型的共享资源有:对象的成员变量、磁盘文件、静态变量等。
为防止出现资源并发冲突的解决思路如下:当共享资源被任务使用时,要对资源提前加锁。所有任务都采用抢占模式,即摸个任务会抢先对共享资源加上一把锁。如果这是一个排它锁,其他任务在资源被解锁前就无法访问。当然,如果是共享锁,当你浏览某些数据时,其他任务也可以同时浏览,但是不允许修改。
JAVA中提供资源同步的关键字:synchronized,它的作用是获取指定对象的监视器锁。
synchronized用户获取当前对象的内置监视器,同步方法与同步方法之间产生互斥现象,同步方法与非同步方法之间不产生互斥现象。即同一个对象之间的两个synchronized方法会产生互斥现象。
Synchronized(Object.class)
Synchronized(Object.class)使用的是类锁,不是对象锁。注意,不要轻易使用Object.class的类锁,因为整个项目中,如果其他业务模块也使用Object.class的类锁,这样就会产生并发冲突。合理使用类锁的基本原则是,尽量使用当前类的监视器锁!
3. 设置守护进程
点击查看代码package com.icss.守护者线程;
public class Daemon {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
while(true) {
System.out.println(Thread.currentThread().getId() + ",run...");
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
});
t1.setDaemon(true);
t1.start();
Thread t2 = new Thread(new Runnable() {
public void run() {
for(int i=0;i<5;i++) {
System.out.println(Thread.currentThread().getId() + ",i=" + i);
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
});
t2.start();
System.err.println( Thread.currentThread().getName() + "-主线程结束....");
}
}
#设置线程的优先级
点击查看代码package com.icss.线程优先级;
import java.math.BigDecimal;
public class FloatArithmetic implements Runnable{
private int priority;
public FloatArithmetic(int priority) {
this.priority = priority;
}
public void run() {
BigDecimal value = new BigDecimal("0");
//按照参数传递值修改当前线程优先级.
Thread.currentThread().setPriority(priority);
BigDecimal pi = new BigDecimal(Math.PI);
BigDecimal e = new BigDecimal(Math.E);
//足够耗时的计算,使任务调度可以反应.
for (int i = 0; i < 3000; i++) {
for (int j = 0; j < 3000; j++) {
value = value.add(pi.add(e).divide(pi,4));
}
}
Thread self = Thread.currentThread();
System.out.println("线程编号为" + self.getId() + ", 优先级为"
+ self.getPriority() + ", 计算结果为" + value.doubleValue());
}
public static void main(String[] args) {
new Thread(new FloatArithmetic(Thread.MIN_PRIORITY)).start();
new Thread(new FloatArithmetic(Thread.MIN_PRIORITY)).start();
new Thread(new FloatArithmetic(Thread.MIN_PRIORITY)).start();
new Thread(new FloatArithmetic(Thread.MIN_PRIORITY)).start();
new Thread(new FloatArithmetic(Thread.NORM_PRIORITY)).start();
new Thread(new FloatArithmetic(Thread.MAX_PRIORITY)).start();
}
}
#同一个类的两个静态方法互斥
同一个类之间的两个synchronized静态方法通过synchronized方法获取当前类(class extends object)的内置锁,即object对象的内置监视器来产生互斥作用。
#模拟售卖火车票
TicketClass
点击查看代码package com.icss.train3;
public class Ticket {
private String tno;
public String getTno() {
return tno;
}
public Ticket(String tno) {
this.tno = tno;
}
}
#窗口Class
点击查看代码package com.icss.train3;
class Curtain extends Thread {
private String cno;
public String getCno() {
return cno;
}
public Curtain(String cno,Runnable runable) {
super(runable); //给父类的任务赋值
this.cno = cno;
}
}
#售卖火车票
点击查看代码package com.icss.train3;
import java.util.LinkedList;
public class TicketTask implements Runnable{
private LinkedList<Ticket> tickets;
public TicketTask(LinkedList<Ticket> tickets) {
this.tickets = tickets;
}
public void run() {
while(this.tickets.size() > 0) {
synchronized (this) {
Ticket tick = tickets.removeLast();
System.out.println("窗口" + Thread.currentThread().getId()
+ "售出:" + tick.getTno());
}
try {
Thread.sleep(100);
} catch (Exception e) { }
}
}
}
#main
点击查看代码package com.icss.train3;
import java.util.LinkedList;
public class Test {
public static void main(String[] args) {
LinkedList<Ticket> ticks = new LinkedList<>();
for(int i=0;i<50;i++) {
Ticket tick = new Ticket("t" + i);
ticks.add(tick);
}
new Curtain("c1",new TicketTask(ticks) ).start();
new Curtain("c2",new TicketTask(ticks) ).start();
new Curtain("c3",new TicketTask(ticks) ).start();
}
}
点击查看代码窗口c1,9售出 50
窗口c3,11售出 49
窗口c2,10售出 48
窗口c3,11售出 47
窗口c1,9售出 46
窗口c2,10售出 45
窗口c1,9售出 44
窗口c2,10售出 43
窗口c3,11售出 42
窗口c1,9售出 41
窗口c3,11售出 40
窗口c2,10售出 39
窗口c2,10售出 38
3.多线程通信:wait()和notify()
java.lang.Object类中内置了用于线程通讯的方法:wait() 和 notify()、notifyAll()
点击查看代码public final native void notify();
public final native void notifyAll();
public final void wait() throws InterruptedException {
wait(0);
}
点击查看代码
package com.icss.ui;
public class TestWait {
public static void main(String[] args) {
Object object = new Object();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getId() + ",i=" + i);
if (i == 5) {
synchronized (object) { //先获取object对象的监视器锁
try {
System.out.println(Thread.currentThread().getId()
+ "开始等待...");
object.wait(); //使当前线程进入阻塞等待状态....
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getId() + " running...");
try {
Thread.sleep(1000);
synchronized (object) { //先获取object对象的监视器锁
System.out.println(Thread.currentThread().getId()
+ ",发送notify通知...");
object.notify();
}
} catch (Exception e) {
}
}
}).start();
System.out.println("主线程:" + Thread.currentThread().getId() + "结束...");
}
}
3.1 wait()和notify()实例:厨师与侍者
#Chef
点击查看代码package com.icss.chef2;
class Chef implements Runnable {
private Order order;
private Waiter waiter;
public void setOrder(Order order) {
this.order = order;
}
public void setWaiter(Waiter waiter) {
this.waiter = waiter;
}
public void run() {
while (true) {
synchronized (this) {
try {
System.out.println("厨师空闲等待中...");
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
//厨师收到订单通知
int rand = (int) (Math.random() * 800);
try {
Thread.sleep(rand);
} catch (Exception e) {
}
System.out.println("厨师做菜完成,通知waiter取菜...");
synchronized (this.waiter) {
waiter.setMsgID(2);
waiter.notify();
}
}
}
}
#waiter
点击查看代码package com.icss.chef2;
class Waiter implements Runnable {
private Order order;
private Chef chef;
private int msgID = 1; //如果新订单通知id=1, 如果是取菜通知id=2
public void setMsgID(int msgID) {
this.msgID = msgID;
}
public void setChef(Chef chef) {
this.chef = chef;
}
public void setOrder(Order order) {
this.order = order;
}
public void run() {
while (true) {
synchronized (this) {
try {
System.out.println("服务员空闲等待中...");
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
if (msgID == 1) {
//服务员收到新订单通知
System.out.println("waiter收到订单:"
+ this.order.getDno() + "," + this.order.getInfo());
//通知厨师做菜
synchronized (chef) {
System.out.println("waiter通知厨师做菜...");
chef.setOrder(order);
chef.notify();
}
} else {
//服务员收到了取菜通知
System.out.println("waiter取菜给顾客....");
}
}
}
}
#Order
点击查看代码package com.icss.chef2;
import java.io.Serializable;
public class Order implements Serializable {
private String dno;
private String info;
public String getDno() {
return dno;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public Order(String dno) {
this.dno = dno;
}
}
#Restaurant
点击查看代码package com.icss.chef2;
class Restaurant implements Runnable {
private Waiter waiter;
public void setWaiter(Waiter waiter) {
this.waiter = waiter;
}
public void run() {
while (true) {
int rand = (int) (Math.random() * 5000);
try {
System.out.println("饭店等待顾客中---------------");
Thread.sleep(rand);
String dno = "d" + System.currentTimeMillis();
Order order = new Order(dno);
order.setInfo("宫保鸡丁一份...");
System.out.println("顾客来了,通知服务员点菜,生成订单:" + dno);
synchronized (waiter) {
waiter.setOrder(order); //把订单给服务员
waiter.setMsgID(1);
waiter.notify();
}
} catch (Exception e) {
}
}
}
}
#Main
点击查看代码package com.icss.chef2;
public class Test {
public static void main(String[] args) {
Chef chef = new Chef();
Waiter waiter = new Waiter();
waiter.setChef(chef);
chef.setWaiter(waiter);
Restaurant rest = new Restaurant();
rest.setWaiter(waiter);
new Thread(waiter).start();
new Thread(chef).start();
new Thread(rest).start();
}
}
#运行结果
点击查看代码Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
厨师-10,接到新订单,开始做菜...
厨师-10,通知waiter取食物
Waiter-9,收到通知,取走订单
Waiter-9,等待中
没有食物了,结束!
3.2 join线程排队(应用场景:处理紧急任务)
线程A调用线程B对象的join()方法,会导致线程A的运行中断,直到线程B运行完成或超时,线程A才继续运行。
#Main函数
点击查看代码package com.icss.join;
public class Test {
public static void main(String[] args) {
Sleeper sleeper = new Sleeper();
Joiner joiner = new Joiner();
sleeper.setJoiner(joiner);
sleeper.start();
joiner.start();
}
}
#分别定义Sleeper和Joiner
#Sleeper
点击查看代码package com.icss.join;
class Sleeper extends Thread {
private Joiner joiner;
public void setJoiner(Joiner joiner) {
this.joiner = joiner;
}
public void run() {
System.out.println("Sleeper线程id="
+ Thread.currentThread().getId() + " run...");
try {
for (int i = 0; i < 10; i++) {
if (i == 5 && joiner != null) {
System.out.println("joiner加入,线程" +
Thread.currentThread().getId() + "被阻塞");
joiner.join();
}
Thread.sleep(100);
System.out.println("线程"
+ Thread.currentThread().getId() + "---i=" + i);
}
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getId() + " end...");
}
}
#Joiner
点击查看代码package com.icss.join;
class Joiner extends Thread {
public void run() {
System.out.println("Joiner 线程id="
+ Thread.currentThread().getId() + " run...");
try {
for (int i = 0; i < 10; i++) {
Thread.sleep(100);
System.out.println("线程"
+ Thread.currentThread().getId() + "---k=" + i);
}
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getId() + " end...");
}
}
#运行结果
点击查看代码Joiner 线程id=10 run...
Sleeper线程id=9 run...
线程9---i=0
线程10---k=0
线程10---k=1
线程9---i=1
线程10---k=2
线程9---i=2
线程9---i=3
线程10---k=3
线程9---i=4
joiner加入,线程9被阻塞
线程10---k=4
线程10---k=5
线程10---k=6
线程10---k=7
线程10---k=8
线程10---k=9
10 end...
线程9---i=5
线程9---i=6
线程9---i=7
线程9---i=8
线程9---i=9
9 end...
注:join(long millis)方法中传入的超时参数不能为负数,否则将会抛出非法参数异常。如果 millis 参数为0,则表示永远等待。
3.3 线程中断
点击查看代码package com.icss.interrupt;
public class TestInterrupt {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("收到中断通知,结束线程...");
break;
} else {
System.out.println(Thread.currentThread().getId()
+ ",i=" + i);
try {
Thread.sleep(100);
} catch (Exception e) {
}
}
}
}
});
t.start();
try {
Thread.sleep(500);
} catch (Exception e) {
}
t.interrupt();
System.out.println(t.getId() + "中断状态:" + t.isInterrupted());
}
}
3.3.1 停止正在运行的线程
点击查看代码package com.icss.interrupt;
public class StopTask implements Runnable {
private boolean flag = true;
public void run() {
int i = 0;
while (flag) {
try {
Thread.sleep(200);
} catch (Exception e) {
}
i++;
System.out.println(Thread.currentThread().getId() + "--i=" + i);
}
}
public void stop() {
flag = false;
System.out.println(Thread.currentThread().getId() + "发出停止命令...");
}
public static void main(String[] args) {
StopTask task = new StopTask();
new Thread(task).start();
try {
Thread.sleep(5000);
task.stop();
} catch (Exception e) {
}
}
}
3.3.2 CountDownLatch计数器
CountDownLatch计数器是java.util.concurrent包中的线程工具类,用于允许一个或多个线程阻塞等待,直到其他线程工作完成才开始执行。
点击查看代码/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
package java.util.concurrent;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
* A synchronization aid that allows one or more threads to wait until
* a set of operations being performed in other threads completes.
*
* <p>A {@code CountDownLatch} is initialized with a given <em>count</em>.
* The {@link #await await} methods block until the current count reaches
* zero due to invocations of the {@link #countDown} method, after which
* all waiting threads are released and any subsequent invocations of
* {@link #await await} return immediately. This is a one-shot phenomenon
* -- the count cannot be reset. If you need a version that resets the
* count, consider using a {@link CyclicBarrier}.
*
* <p>A {@code CountDownLatch} is a versatile synchronization tool
* and can be used for a number of purposes. A
* {@code CountDownLatch} initialized with a count of one serves as a
* simple on/off latch, or gate: all threads invoking {@link #await await}
* wait at the gate until it is opened by a thread invoking {@link
* #countDown}. A {@code CountDownLatch} initialized to <em>N</em>
* can be used to make one thread wait until <em>N</em> threads have
* completed some action, or some action has been completed N times.
*
* <p>A useful property of a {@code CountDownLatch} is that it
* doesn't require that threads calling {@code countDown} wait for
* the count to reach zero before proceeding, it simply prevents any
* thread from proceeding past an {@link #await await} until all
* threads could pass.
*
* <p><b>Sample usage:</b> Here is a pair of classes in which a group
* of worker threads use two countdown latches:
* <ul>
* <li>The first is a start signal that prevents any worker from proceeding
* until the driver is ready for them to proceed;
* <li>The second is a completion signal that allows the driver to wait
* until all workers have completed.
* </ul>
*
* <pre> {@code
* class Driver { // ...
* void main() throws InterruptedException {
* CountDownLatch startSignal = new CountDownLatch(1);
* CountDownLatch doneSignal = new CountDownLatch(N);
*
* for (int i = 0; i < N; ++i) // create and start threads
* new Thread(new Worker(startSignal, doneSignal)).start();
*
* doSomethingElse(); // don't let run yet
* startSignal.countDown(); // let all threads proceed
* doSomethingElse();
* doneSignal.await(); // wait for all to finish
* }
* }
*
* class Worker implements Runnable {
* private final CountDownLatch startSignal;
* private final CountDownLatch doneSignal;
* Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
* this.startSignal = startSignal;
* this.doneSignal = doneSignal;
* }
* public void run() {
* try {
* startSignal.await();
* doWork();
* doneSignal.countDown();
* } catch (InterruptedException ex) {} // return;
* }
*
* void doWork() { ... }
* }}</pre>
*
* <p>Another typical usage would be to divide a problem into N parts,
* describe each part with a Runnable that executes that portion and
* counts down on the latch, and queue all the Runnables to an
* Executor. When all sub-parts are complete, the coordinating thread
* will be able to pass through await. (When threads must repeatedly
* count down in this way, instead use a {@link CyclicBarrier}.)
*
* <pre> {@code
* class Driver2 { // ...
* void main() throws InterruptedException {
* CountDownLatch doneSignal = new CountDownLatch(N);
* Executor e = ...
*
* for (int i = 0; i < N; ++i) // create and start threads
* e.execute(new WorkerRunnable(doneSignal, i));
*
* doneSignal.await(); // wait for all to finish
* }
* }
*
* class WorkerRunnable implements Runnable {
* private final CountDownLatch doneSignal;
* private final int i;
* WorkerRunnable(CountDownLatch doneSignal, int i) {
* this.doneSignal = doneSignal;
* this.i = i;
* }
* public void run() {
* try {
* doWork(i);
* doneSignal.countDown();
* } catch (InterruptedException ex) {} // return;
* }
*
* void doWork() { ... }
* }}</pre>
*
* <p>Memory consistency effects: Until the count reaches
* zero, actions in a thread prior to calling
* {@code countDown()}
* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
* actions following a successful return from a corresponding
* {@code await()} in another thread.
*
* @since 1.5
* @author Doug Lea
*/
public class CountDownLatch {
/**
* Synchronization control For CountDownLatch.
* Uses AQS state to represent count.
*/
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
private final Sync sync;
/**
* Constructs a {@code CountDownLatch} initialized with the given count.
*
* @param count the number of times {@link #countDown} must be invoked
* before threads can pass through {@link #await}
* @throws IllegalArgumentException if {@code count} is negative
*/
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
/**
* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
*
* <p>If the current count is zero then this method returns immediately.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of two things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
* </ul>
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* @throws InterruptedException if the current thread is interrupted
* while waiting
*/
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted},
* or the specified waiting time elapses.
*
* <p>If the current count is zero then this method returns immediately
* with the value {@code true}.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of three things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread; or
* <li>The specified waiting time elapses.
* </ul>
*
* <p>If the count reaches zero then the method returns with the
* value {@code true}.
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* <p>If the specified waiting time elapses then the value {@code false}
* is returned. If the time is less than or equal to zero, the method
* will not wait at all.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the {@code timeout} argument
* @return {@code true} if the count reached zero and {@code false}
* if the waiting time elapsed before the count reached zero
* @throws InterruptedException if the current thread is interrupted
* while waiting
*/
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
/**
* Decrements the count of the latch, releasing all waiting threads if
* the count reaches zero.
*
* <p>If the current count is greater than zero then it is decremented.
* If the new count is zero then all waiting threads are re-enabled for
* thread scheduling purposes.
*
* <p>If the current count equals zero then nothing happens.
*/
public void countDown() {
sync.releaseShared(1);
}
/**
* Returns the current count.
*
* <p>This method is typically used for debugging and testing purposes.
*
* @return the current count
*/
public long getCount() {
return sync.getCount();
}
/**
* Returns a string identifying this latch, as well as its state.
* The state, in brackets, includes the String {@code "Count ="}
* followed by the current count.
*
* @return a string identifying this latch, as well as its state
*/
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
}
CountDownLatch类的构造函数,需要输入一个等待任务数量。每完成一项任务,就调用一次countDown()方法。某个任务A启动后,调用await()方法,进入阻塞等待状态。当代用getCount()方法,发现等待任务数量为0是,任务A开始执行最后的任务。
应用场景:汽车厂商生产一辆汽车需要多种配件组装,包括车身、发动机等。只有前面的各个环节都完成之后才能进入总装环节。
#Main函数
点击查看代码package com.icss.countdown;
import java.util.concurrent.CountDownLatch;
public class Test {
public static void main(String[] args) {
CountDownLatch cl = new CountDownLatch(10);
WaitingTask w = new WaitingTask(cl);
new Thread(w).start(); //汽车总装任务
for (int i = 0; i < 10; i++) {
WorkingTask work = new WorkingTask(cl);
new Thread(work).start();
}
}
}
#WaitingTask
点击查看代码package com.icss.countdown;
import java.util.concurrent.CountDownLatch;
public class WaitingTask implements Runnable {
private CountDownLatch cl;
public WaitingTask(CountDownLatch cl) {
this.cl = cl;
}
public void run() {
try {
System.out.println(Thread.currentThread().getId()
+ "阻塞等待其他任务完成....");
cl.await();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getId()
+ "汽车总装完成,汽车出厂....");
} catch (Exception e) {
e.printStackTrace();
}
}
}
#WorkingTask
点击查看代码package com.icss.countdown;
import java.util.concurrent.CountDownLatch;
public class WorkingTask implements Runnable {
private CountDownLatch cl;
public WorkingTask(CountDownLatch cl) {
this.cl = cl;
}
public void run() {
try {
int r = (int) (Math.random() * 10);
Thread.sleep(r * 1000);
System.out.println(Thread.currentThread().getId() + "任务完成");
cl.countDown(); //任务完成后,计数器减一
} catch (Exception e) {
e.printStackTrace();
}
}
}