setDaemon(boolean on)方法可以方便的设置线程的Daemon模式,true为Daemon模式,false为User模式。
这就是守护线程,守护着最后一个用户线程,如果没有用户线程了,他也没作用了,退出。
线程名,线程组,是否为守护线程
Future 接口允许表示已经完成的任务、正在执行过程中的任务或者尚未开始执行的任务。通过 Future 接口,可以尝试取消尚未完成的任务,查询任务已经完成还是取消了,以及提取(或等待)任务的结果值。 FutureTask 类实现了 Future,一些提交方法(如 ExecutorService.submit())除了提交任务之外,还将返回 Future 接口。 Future.get() 方法检索任务计算的结果(或如果任务完成,但有异常,则抛出 ExecutionException)。如果任务尚未完成,那么 Future.get() 将被阻塞,直到任务完成;如果任务已经完成,那么它将立即返回结果。
CyclicBarrier 类可以帮助同步,它允许一组线程等待整个线程组到达公共屏障点。
BlockingQueue:阻塞队列,该类主要提供了两个方法put()和take(),前者将一个对象放到队列中,如果队列已经满了,就等待直到有空闲节点;后者从head取一个对象,如果没有对象,就等待直到有可取的对象。
J2SE 5.0提供了一组atomic class来帮助我们简化同步处理。AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。
AtomicInteger:一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。
package cn.php.test;
import java.util.concurrent.CountDownLatch;
/**
*value++线程不安全示例和CountDownLatch的用法
*/
class Counter {
private int value;
public synchronized int increase() {
return value++;
}
public int unSyncIncrease() {
return value++;
}
public int get() {
return value;
}
}
public class Test4 {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
final CountDownLatch latch = new CountDownLatch(100);
final Counter counter = new Counter();
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
counter.increase();
//counter.unSyncIncrease();
}
latch.countDown();
}
}).start();
}
latch.await();
long end = System.currentTimeMillis();
System.out.println("Elapsed: " + (end - start) + "ms, value=" + counter.get());
}
}
package cn.php.test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
/**
*AtomicInteger线程安全示例和CountDownLatch的用法
*/
class Counter1 {
private AtomicInteger value = new AtomicInteger();
public int increase() {
return value.incrementAndGet();
}
public int get() {
return value.get();
}
}
public class Test5 {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
final CountDownLatch latch = new CountDownLatch(100);
final Counter1 counter = new Counter1();
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
counter.increase();
}
latch.countDown();
}
}).start();
}
latch.await();
long end = System.currentTimeMillis();
System.out.println("Elapsed: " + (end - start) + "ms, value=" + counter.get());
}
}
CountDownLatch是一个倒数计数的锁,当倒数到0时触发事件,也就是开锁,其他人就可以进入了。
使用Callable和Future实现线程等待和多线程返回值
package cn.php.test;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Test6 {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
System.out.println("start main thread");
final ExecutorService exec = Executors.newFixedThreadPool(5);
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println(" start new thread.");
Thread.sleep(1000 * 5);
System.out.println(" end new thread.");
return "some value.";
}
};
Future<String> future = exec.submit(callable);
Thread.sleep(1000 * 2);
System.out.println(future.get()); // 阻塞,并待子线程结束,
exec.shutdown();
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("end main thread");
}
}
package cn.php.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Test6 {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
System.out.println("start main thread");
final ExecutorService exec = Executors.newFixedThreadPool(5);
List<Future<String>> tasks = new ArrayList<Future<String>>();
for (int i = 0; i < 5; i++) {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println(" start new thread.");
Thread.sleep(1000 * 5);
System.out.println(" end new thread.");
return "some value.";
}
};
tasks.add(exec.submit(callable));
}
Thread.sleep(1000 * 2);
for(Future<String> task:tasks){
System.out.println(task.get()); //阻塞
}
exec.shutdown();
exec.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("end main thread");
}
}
package cn.php.test;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* CompletionService,它会首先取完成任务的线程.take() 获取并移除表示下一个已完成任务的 Future,如果目前不存在这样的任务,则等待。
*/
public class Test7 {
public static void main(String[] args) throws InterruptedException,
ExecutionException {
ExecutorService pool = Executors.newFixedThreadPool(5);
CompletionService<String> CompletionService = new ExecutorCompletionService<String>(
pool);
for (int i = 0; i < 5; i++) {
final int no = i;
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("task" + no + "start");
return "task" + no;
}
};
CompletionService.submit(callable);
}
System.out.println("Show web content");
for (int i = 0; i < 5; i++) {
Future<String> task = CompletionService.take();
String img = task.get();
System.out.println(img);
}
System.out.println("End");
// 关闭线程池
pool.shutdown();
}
}
拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。下面的例子只允许5个线程同时进入执行acquire()和release()之间的代码
package cn.php.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* 拿到信号量的线程可以进入代码,否则就等待。通过acquire()和release()获取和释放访问许可。下面的例子只允许5个线程同时进入执行acquire()和release()之间的代码
*/
public class Test7 {
public static void main(String[] args) {
final Semaphore semp = new Semaphore(5);
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 20; i++) {
final int no = i;
pool.submit(new Runnable() {
@Override
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println("Accessing" + no);
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放
semp.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
pool.shutdown();
}
}
挂起的原因可能是如下几种情况:
(1)通过调用sleep()方法使线程进入休眠状态,线程在指定时间内不会运行。
(2)通过调用join()方法使线程挂起,使自己等待另一个线程的结果,直到另一个线程执行完毕为止。
(3)通过调用wait()方法使线程挂起,直到线程得到了notify()和notifyAll()消息,线程才会进入“可执行”状态。
(4)使用suspend挂起线程后,可以通过resume方法唤醒线程。
虽然suspend和resume可以很方便地使线程挂起和唤醒,但由于使用这两个方法可能会造成死锁,因此,这两个方法被标识为 deprecated(抗议)标记,这表明在以后的jdk版本中这两个方法可能被删除,所以尽量不要使用这两个方法来操作线程。
调用sleep()、yield()、suspend()的时候并没有被释放锁
调用wait()的时候释放当前对象的锁
wait()方法表示,放弃当前对资源的占有权,一直等到有线程通知,才会运行后面的代码。
notify()方法表示,当前的线程已经放弃对资源的占有,通知等待的线程来获得对资源的占有权,但是只有一个线程能够从wait状态中恢复,然后继续运行wait()后面的语句。
notifyAll()方法表示,当前的线程已经放弃对资源的占有,通知所有的等待线程从wait()方法后的语句开始运行。
等待和锁实现资源竞争
等待机制与锁机制是密切关联的,对于需要竞争的资源,首先用synchronized确保这段代码只能一个线程执行,可以再设置一个标志位condition判断该资源是否准备好,如果没有,则该线程释放锁,自己进入等待状态,直到接收到notify,程序从wait处继续向下执行。
以上程序表示只有一个线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A释放该锁,进入wait()。
在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:
需要注意的是:
# 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
# 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。
# 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
# 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
# obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
# 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
锁和唤醒:唤醒需要此锁的线程
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。
线程总体分两类:用户线程和守候线程。
当所有用户线程执行完毕的时候,JVM自动关闭。但是守候线程却不独立于JVM,守候线程一般是由操作系统或者用户自己创建的
thread.yield():yield()方法只是把线程的状态有执行状态打回可运行状态, ,并不保证下一个运行的线程就一定不是该线程, 以考虑用Thread.sleep(long millis);方法强制当前线程睡眠至少millis毫秒
Join()方法: 阻塞调用线程,直到某个线程终止或经过了指定时间为止
Join的官方解释: 阻塞调用线程,直到某个线程终止或经过了指定时间为止
Q:谁是调用线程?
A:Join代码写在那,哪个就是调用线程
Q:某个线程又是指的是谁?
A:如本例thread1执行了Join方法,thread1为某个线程
join(long millis):执行Join方法的线程等待最长为 millis 毫秒
package cn.php.test;
class RunnerTest implements Runnable{
int a =0;
@Override
public void run() {
for(int i=0;i<5;i++){
try {
//Thread.sleep(10);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
a=a+1;
}
}
public int getA() {
return a;
}
}
public class Test9 {
public static void main(String[] args) throws InterruptedException {
RunnerTest runnerTest = new RunnerTest();
Thread t = new Thread(runnerTest);
t.start();
//t.join();
t.join(10);
System.out.println(runnerTest.getA());
}
}
package cn.php.test;
class CustomThread1 extends Thread {
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
try {
for (int i = 0; i < 5; i++) {
System.out.println(threadName + " loop at " + i);
Thread.sleep(1000);
}
System.out.println(threadName + " end.");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
class CustomThread extends Thread {
CustomThread1 t1;
public CustomThread(CustomThread1 t1) {
this.t1 = t1;
}
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
try {
t1.join();
System.out.println(threadName + " end.");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
public class JoinTestDemo {
public static void main(String[] args) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
CustomThread1 t1 = new CustomThread1();
CustomThread t = new CustomThread(t1);
try {
t1.start();
Thread.sleep(2000);
t.start();
t.join(); // 在代碼2里,將此處注釋掉
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(threadName + " end!");
}
}
线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。
线程安全类:当一个类已经很好的同步以保护它的数据时,这个类就称为“线程安全的”。
线程的同步和互斥
解除所有那些在该对象上调用wait方法的线程的阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
随机选择一个在该对象上调用wait方法的线程,解除其阻塞状态。该方法只能在同步方法或同步块内部调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
导致线程进入等待状态,直到它被其他线程通过notify()或者notifyAll唤醒。该方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
导致线程进入等待状态直到它被通知或者经过指定的时间。这些方法只能在同步方法中调用。如果当前线程不是锁的持有者,该方法抛出一个IllegalMonitorStateException异常。
Object.wait()和Object.notify()和Object.notifyall()必须写在synchronized方法内部或者synchronized块内部,这是因为:这几个方法要求当前正在运行object.wait()方法的线程拥有object的对象锁。
/**
* Java线程:线程的调度-合并
*
* @author leizhimin 2009-11-4 9:02:40
*/
publicclass Test {
publicstaticvoid main(String[] args) {
Thread t1 = new MyThread1();
t1.start();
for (int i = 0; i < 20; i++) {
System.out.println("主线程第" + i +"次执行!");
if (i > 2)try {
//t1线程合并到主线程中,主线程停止执行过程,转而执行t1线程,直到t1执行完毕后继续。
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyThread1 extends Thread {
publicvoid run() {
for (int i = 0; i < 10; i++) {
System.out.println("线程1第" + i + "次执行!");
}
}
}
守护线程:守护线程与普通线程写法上基本么啥区别,调用线程对象的方法setDaemon(true),则可以将其设置为守护线程。
守护线程使用的情况较少,但并非无用,举例来说,JVM的垃圾回收、内存管理等线程都是守护线程。还有就是在做数据库应用时候,使用的数据库连接池,连接池本身也包含着很多后台线程,监控连接个数、超时时间、状态等等。
当正在运行的线程都是守护线程时,Java虚拟机退出。
package cn.php.test;
/**
* Java线程:线程的调度-守护线程
*
* @author leizhimin 2009-11-4 9:02:40
*/
public class Test9 {
public static void main(String[] args) {
Thread t1 = new MyCommon();
Thread t2 = new Thread(new MyDaemon());
t2.setDaemon(true); //设置为守护线程
t2.start();
t1.start();
}
}
class MyCommon extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("线程1第" + i + "次执行!");
try {
Thread.sleep(7);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyDaemon implements Runnable {
public void run() {
for (long i = 0; i < 9999999L; i++) {
System.out.println("后台线程第" + i +"次执行!");
try {
Thread.sleep(7);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
前台线程是保证执行完毕的,后台线程还没有执行完毕就退出了。
void notify()
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法。
void wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者超过指定的时间量。
void wait(long timeout,int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify()方法或 notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
//关闭线程池
pool.shutdown();
可变尺寸的线程池Executors.newCachedThreadPool();
可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。
执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。
package cn.php.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Java线程:锁
*
* @author leizhimin 2009-11-5 10:57:29
*/
public class Test {
public static void main(String[] args) {
//创建并发访问的账户
MyCount myCount = new MyCount("95599200901215522", 10000);
//创建一个锁对象
Lock lock = new ReentrantLock(); //不区分读写,称这种锁为普通锁
//创建一个线程池
ExecutorService pool = Executors.newCachedThreadPool();
//创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊
User u1 = new User("张三", myCount, -4000, lock);
User u2 = new User("张三他爹", myCount, 6000, lock);
User u3 = new User("张三他弟", myCount, -8000, lock);
User u4 = new User("张三", myCount, 800, lock);
//在线程池中执行各个用户的操作
pool.execute(u1);
pool.execute(u2);
pool.execute(u3);
pool.execute(u4);
//关闭线程池
pool.shutdown();
}
}
/**
* 信用卡的用户
*/
class User implements Runnable {
private String name; //用户名
private MyCount myCount; //所要操作的账户
private int iocash; //操作的金额,当然有正负之分了
private Lock myLock; //执行操作所需的锁对象
User(String name, MyCount myCount, int iocash, Lock myLock) {
this.name = name;
this.myCount = myCount;
this.iocash = iocash;
this.myLock = myLock;
}
public void run() {
//获取锁
myLock.lock();
//执行现金业务
System.out.println(name + "正在操作" + myCount +"账户,金额为" + iocash +",当前金额为" + myCount.getCash());
myCount.setCash(myCount.getCash() + iocash);
System.out.println(name + "操作" + myCount +"账户成功,金额为" + iocash +",当前金额为" + myCount.getCash());
//释放锁,否则别的线程没有机会执行了
myLock.unlock();
}
}
/**
* 信用卡账户,可随意透支
*/
class MyCount {
private String oid; //账号
private int cash; //账户余额
MyCount(String oid, int cash) {
this.oid = oid;
this.cash = cash;
}
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public int getCash() {
return cash;
}
public void setCash(int cash) {
this.cash = cash;
}
@Override
public String toString() {
return"MyCount{" +
"oid='" + oid + '\'' +
", cash=" + cash +
'}';
}
}
为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在一定程度上提高了程序的执行效率。
Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止。
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ArrayBlockingQueue;
/**
* Java线程:新特征-阻塞队列
*
* @author leizhimin 2009-11-5 14:59:15
*/
publicclass Test {
publicstaticvoid main(String[] args)throws InterruptedException {
BlockingQueue bqueue = new ArrayBlockingQueue(20);
for (int i = 0; i < 30; i++) {
//将指定元素添加到此队列中,如果没有可用空间,将一直等待(如果有必要)。
bqueue.put(i);
System.out.println("向阻塞队列中添加了元素:" + i);
}
System.out.println("程序到此运行结束,即将退出----");
}
}
输出结果:
向阻塞队列中添加了元素:0
向阻塞队列中添加了元素:1
向阻塞队列中添加了元素:2
向阻塞队列中添加了元素:3
向阻塞队列中添加了元素:4
向阻塞队列中添加了元素:5
向阻塞队列中添加了元素:6
向阻塞队列中添加了元素:7
向阻塞队列中添加了元素:8
向阻塞队列中添加了元素:9
向阻塞队列中添加了元素:10
向阻塞队列中添加了元素:11
向阻塞队列中添加了元素:12
向阻塞队列中添加了元素:13
向阻塞队列中添加了元素:14
向阻塞队列中添加了元素:15
向阻塞队列中添加了元素:16
向阻塞队列中添加了元素:17
向阻塞队列中添加了元素:18
向阻塞队列中添加了元素:19
可以看出,输出到元素19时候,就一直处于等待状态,因为队列满了,程序阻塞了。
这里没有用多线程来演示,没有这个必要。
另外,阻塞队列还有更多实现类,用来满足各种复杂的需求:ArrayBlockingQueue, DelayQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue,具体的API差别也很小。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicLong;
/**
* Java线程:新特征-原子量
*
* @author leizhimin 2009-11-6 9:53:11
*/
publicclass Test {
publicstaticvoid main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(2);
Lock lock = new ReentrantLock(false);
Runnable t1 = new MyRunnable("张三", 2000,lock);
Runnable t2 = new MyRunnable("李四", 3600,lock);
Runnable t3 = new MyRunnable("王五", 2700,lock);
Runnable t4 = new MyRunnable("老张", 600,lock);
Runnable t5 = new MyRunnable("老牛", 1300,lock);
Runnable t6 = new MyRunnable("胖子", 800,lock);
//执行各个线程
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
//关闭线程池
pool.shutdown();
}
}
class MyRunnableimplements Runnable {
privatestatic AtomicLong aLong =new AtomicLong(10000); //原子量,每个线程都可以自由操作
private String name; //操作人
privateint x; //操作数额
private Lock lock;
MyRunnable(String name, int x,Lock lock) {
this.name = name;
this.x = x;
this.lock = lock;
}
publicvoid run() {
lock.lock();
System.out.println(name + "执行了" + x +",当前余额:" + aLong.addAndGet(x));
lock.unlock();
}
}
执行结果:
张三执行了2000,当前余额:12000
王五执行了2700,当前余额:14700
老张执行了600,当前余额:15300
老牛执行了1300,当前余额:16600
胖子执行了800,当前余额:17400
李四执行了3600,当前余额:21000
Process finished with exit code 0
这里使用了一个对象锁,来控制对并发代码的访问。不管运行多少次,执行次序如何,最终余额均为21000,这个结果是正确的。
有关原子量的用法很简单,关键是对原子量的认识,原子仅仅是保证变量操作的原子性,但整个程序还需要考虑线程安全的
主线程等待子线程结束:
package cn.php.test;
import java.util.ArrayList;
import java.util.List;
public class Test2 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 1000; i++) {
list.add(i);
}
List<List<Integer>> splitLists = splitList(list, 400);
List<SubTask> tlist = new ArrayList<SubTask>();
for (List<Integer> ls : splitLists) {
SubTask task = new SubTask(ls);
tlist.add(task);
task.start();
}
for(SubTask st:tlist){
try {
st.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("主线程结束!");
}
private static <T> List<List<T>> splitList(List<T> targe, int size) {
List<List<T>> listArr = new ArrayList<List<T>>();
// 获取被拆分的数组个数
int arrSize = targe.size() % size == 0 ? targe.size() / size : targe
.size() / size + 1;
for (int i = 0; i < arrSize; i++) {
List<T> sub = new ArrayList<T>();
// 把指定索引数据放入到list中
for (int j = i * size; j <= size * (i + 1) - 1; j++) {
if (j <= targe.size() - 1) {
sub.add(targe.get(j));
}
}
listArr.add(sub);
}
return listArr;
}
}
class SubTask extends Thread {
List<Integer> l = new ArrayList<Integer>();
public SubTask(List<Integer> list) {
this.l = list;
}
@Override
public void run() {
for (int i : l) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
package cn.php.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class Test2 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 1000; i++) {
list.add(i);
}
List<List<Integer>> splitLists = splitList(list, 400);
List<SubTask> tlist = new ArrayList<SubTask>();
CountDownLatch count = new CountDownLatch(splitLists.size());
for (List<Integer> ls : splitLists) {
SubTask task = new SubTask(ls, count);
tlist.add(task);
task.start();
}
try {
count.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束!");
}
private static <T> List<List<T>> splitList(List<T> targe, int size) {
List<List<T>> listArr = new ArrayList<List<T>>();
// 获取被拆分的数组个数
int arrSize = targe.size() % size == 0 ? targe.size() / size : targe
.size() / size + 1;
for (int i = 0; i < arrSize; i++) {
List<T> sub = new ArrayList<T>();
// 把指定索引数据放入到list中
for (int j = i * size; j <= size * (i + 1) - 1; j++) {
if (j <= targe.size() - 1) {
sub.add(targe.get(j));
}
}
listArr.add(sub);
}
return listArr;
}
}
class SubTask extends Thread {
List<Integer> l = new ArrayList<Integer>();
CountDownLatch count;
public SubTask(List<Integer> list, CountDownLatch count) {
this.l = list;
this.count = count;
}
@Override
public void run() {
for (int i : l) {
System.out.println(i);
}
count.countDown();
}
}
package cn.php.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test2 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 1000; i++) {
list.add(i);
}
List<List<Integer>> splitLists = splitList(list, 400);
ExecutorService pool = Executors.newFixedThreadPool(5);
CountDownLatch count = new CountDownLatch(splitLists.size());
for (List<Integer> ls : splitLists) {
SubTask task = new SubTask(ls, count);
pool.execute(task);
}
try {
count.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束!");
}
private static <T> List<List<T>> splitList(List<T> targe, int size) {
List<List<T>> listArr = new ArrayList<List<T>>();
// 获取被拆分的数组个数
int arrSize = targe.size() % size == 0 ? targe.size() / size : targe
.size() / size + 1;
for (int i = 0; i < arrSize; i++) {
List<T> sub = new ArrayList<T>();
// 把指定索引数据放入到list中
for (int j = i * size; j <= size * (i + 1) - 1; j++) {
if (j <= targe.size() - 1) {
sub.add(targe.get(j));
}
}
listArr.add(sub);
}
return listArr;
}
}
class SubTask extends Thread {
List<Integer> l = new ArrayList<Integer>();
CountDownLatch count;
public SubTask(List<Integer> list, CountDownLatch count) {
this.l = list;
this.count = count;
}
@Override
public void run() {
for (int i : l) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
count.countDown();
}
}
CyclicBarrier使用:
package cn.php.test;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
public static void main(String[] args) throws IOException,
InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3);
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new Thread(new Runner(barrier, "1号选手")));
executor.submit(new Thread(new Runner(barrier, "2号选手")));
executor.submit(new Thread(new Runner(barrier, "3号选手")));
executor.shutdown();
System.out.println("=======主线程结束=====");
}
}
class Runner implements Runnable {
// 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)
private CyclicBarrier barrier;
private String name;
public Runner(CyclicBarrier barrier, String name) {
super();
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(1000 * (new Random()).nextInt(8));
System.out.println(name + " 准备好了...");
// barrier的await方法,在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(name + " 起跑!");
}
}