Java编程思想 第21章 并发
Posted 张小贱1987
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java编程思想 第21章 并发相关的知识,希望对你有一定的参考价值。
这是在2013年的笔记整理。现在重新拿出来,放在网上,重新总结下。
两种基本的线程实现方式 以及中断
package thread;
/**
*
* @author zjf
* @create_time 2013-12-18
* @use 测试基本的两种线程的实现方式
* 测试中断
*/
public class BasicThreadTest {
public static void main(String[] args) {
Counter c1 = new Counter();
c1.start();
Thread c2 = new Thread(new Countable());
c2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//中断
c1.interrupt();
c2.interrupt();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//此时c1线程已经终止 不能再次start 多次启动一个线程是非法的。java.lang.IllegalThreadStateException
c1.start();
}
/**
*
* @author zjf
* @create_time 2013-12-18
* @use Runnable接口方式的实现
*/
static class Countable implements Runnable{
public void run() {
int i = 0;
while(!Thread.currentThread().isInterrupted())
{
System.out.println(this.toString() + "-------------" + i);
i ++;
}
}
}
/**
*
* @author zjf
* @create_time 2013-12-18
* @use Thread继承方式的实现
*/
static class Counter extends Thread{
public void run() {
int i = 0;
while(!Thread.currentThread().isInterrupted())
{
System.out.println(this.toString() + "-------------" + i);
i ++;
}
}
}
}
中断
- public void interrupt()
中断线程。
如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。
- public static boolean interrupted()
测试当前线程是否已经中断。线程的中断状态 由该方法清除。
- public boolean isInterrupted()
测试线程是否已经中断。线程的中断状态 不受该方法的影响。
测试睡眠被中断
sleep是静态方法。
package thread;
/**
*
* @author zjf
* @create_time 2013-12-18
* @use 测试Sleep方法被中断
*/
public class SleepTest {
/**
* @author zjf
* @create_time 2013-12-18
* @use 测试目的:睡眠时是否可以被中断
* @param args
*/
public static void main(String[] args) {
Thread t = new Thread(new Sleepable());
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt();
}
static class Sleepable implements Runnable{
public void run() {
try {
//睡眠10秒 但是线程开始1秒后被中断 当前线程在睡眠时能够接收到中断 然后退出
Thread.sleep(10000);
} catch (InterruptedException e) {
//如果被中断 就退出
System.out.println("exit");//一秒后退出
}
}
}
}
测试使用yield让步
yield是静态方法。
package thread;
public class YieldTest {
/**
* @author zjf
* @create_time 2013-12-18
* @use 测试yield方法
* @param args
*/
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
for(int i = 1; i < 100; i++)
{
System.out.println("yield-----" + i);
//测试结果显示 使用yield让步与不使用差别不大
Thread.yield();
}
}
}.start();
new Thread() {
@Override
public void run() {
for(int i = 1; i < 100; i++)
{
System.out.println("notyield-----" + i);
}
}
}.start();
}
}
测试cached线程池
newCachedThreadPool:创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。
CachedThreadPool一般会创建所需数量的线程,并且会复用,这是选择的首选。
package thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPoolTest {
/**
* @author zjf
* @create_time 2013-12-18
* @use 测试Cached线程池
* @param args
*/
public static void main(String[] args) {
/*
* cached线程池不能设置拥有线程的数量
*/
ExecutorService es = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
es.execute(new Countable(i));
}
/*
* 因为要复用线程 所以线程执行完任务之后不会立刻关闭 而是等待一分钟(可配置)
* 的时间 如果在这一分钟期间没有新的任务要执行 会自动关闭
* shutdown标明不会再有新的任务加入 所以加入shutdown代码之后任务执行之后就会关闭线程
* 不会等待一分钟
*/
es.shutdown();
}
static class Countable implements Runnable {
private int i;
public Countable(int i) {
this.i = i;
}
public void run() {
System.out.println("第" + i + "启动的线程的ID是"
+ Thread.currentThread().getId());
/**
* 输出为
第0启动的线程的ID是7
第2启动的线程的ID是9
第1启动的线程的ID是8
第3启动的线程的ID是10
第4启动的线程的ID是11
第5启动的线程的ID是12
第6启动的线程的ID是13
第8启动的线程的ID是8
第7启动的线程的ID是9
第9启动的线程的ID是10
可见 在地8 9 10个线程的时候 复用了第1 2 3个线程。
这建立在第1 2 3个线程已经运行完的基础上。
*/
}
}
}
shutdown和shutdownnow
shutdown:
- 阻止加入新的任务。
- 结束已经完成任务的空闲线程,直到所有任务执行完毕,关闭所有线程为止。
shutdownnow:
- 完成shutdown的功能。
- 向每个未完成的线程发布中断命令。
- 返回未执行的任务列表
shutdownnow
package thread;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ShutdownNowTest {
/**
* @author zjf
* @create_time 2014-2-18
* @use
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(3);
for(int i = 0; i < 10; i ++)
{
es.execute(new Countable(i));
}
TimeUnit.SECONDS.sleep(1);
//返回等待的任务列表
List<Runnable> countList = es.shutdownNow();
for(Runnable r : countList)
{
System.out.println(r.toString() + " is not done...");
}
}
}
class Countable implements Runnable{
private int i;
public Countable(int i) {
this.i = i;
}
public int getI() {
return i;
}
@Override
public String toString() {
return "thread, id : " + i;
}
public void run() {
try {
System.out.println(this.toString() + " is start to run...");
TimeUnit.MILLISECONDS.sleep(500);
System.out.println(this.toString() + " is done...");
} catch (InterruptedException e) {
System.out.println(this.toString() + " is interrupted...");
}
}
}
/** 输出
thread, id : 0 is start to run...
thread, id : 1 is start to run...
thread, id : 2 is start to run...
thread, id : 0 is done...
thread, id : 1 is done...
thread, id : 2 is done...
thread, id : 3 is start to run...
thread, id : 4 is start to run...
thread, id : 5 is start to run...
thread, id : 5 is done...
thread, id : 3 is done...
thread, id : 4 is done...
thread, id : 6 is start to run...
thread, id : 6 is interrupted...
thread, id : 7 is not done...
thread, id : 8 is not done...
thread, id : 9 is not done...
*/
测试ThreadFactory
package thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class ThreadFactoryTest {
/**
* @author zjf
* @create_time 2013-12-18
* @use 测试Cached线程池
* @param args
*/
public static void main(String[] args) {
ThreadFactory threadFactory = new MyThreadFactory();
ExecutorService es = Executors.newCachedThreadPool(threadFactory);
for (int i = 0; i < 10; i++) {
es.execute(new Countable(i));
}
es.shutdown();
}
static class Countable implements Runnable {
private int i;
public Countable(int i) {
this.i = i;
}
public void run() {
System.out.println("第" + i + "个任务正在运行!");
}
}
static class MyThreadFactory implements ThreadFactory {
private static int count = 0;
public Thread newThread(Runnable r) {
return new MyThread(r,count++);
}
};
static class MyThread extends Thread
{
private Runnable target;
private int count;
public MyThread(Runnable target, int count) {
super();
this.target = target;
this.count = count;
}
@Override
public void run() {
System.out.println("第" + count + "个线程启动!" );
if(target != null)
{
target.run();
}
System.out.println("第" + count + "个线程结束!" );
}
}
}
/*
* 输出结果
第0个线程启动!
第1个线程启动!
第2个线程启动!
第3个线程启动!
第0个任务正在运行!
第1个任务正在运行!
第2个任务正在运行!
第4个线程启动!
第3个任务正在运行!
第5个线程启动!
第4个任务正在运行!
第5个任务正在运行!
第8个任务正在运行!
第6个线程启动!
第7个任务正在运行!
第7个线程启动!
第6个任务正在运行!
第9个任务正在运行!
第7个线程结束!
第0个线程结束!
第3个线程结束!
第6个线程结束!
第5个线程结束!
第1个线程结束!
第4个线程结束!
第2个线程结束!
证明: Countable中的run方法被执行了10次
MyThread中的run方法只被执行了9次
原因:CachedThreadPool在需要的时候会调用ThreadFactory的newThread方法 但是也会用到缓存
*/
测试FixedThreadPool
newFixedThreadPool:创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。(这与cacheThreadPool不一样)
package thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolTest {
/**
* @author zjf
* @create_time 2013-12-18
* @use 测试Fixed线程池
* @param args
*/
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
es.execute(new Countable(i));
}
es.shutdown();
}
static class Countable implements Runnable {
private int i;
public Countable(int i) {
this.i = i;
}
public void run() {
System.out.println("第" + i + "启动的线程的ID是"
+ Thread.currentThread().getId());
}
}
}
/*
第0启动的线程的ID是7
第2启动的线程的ID是9
第1启动的线程的ID是8
第3启动的线程的ID是7
第4启动的线程的ID是9
*/
SingleThreadExecutor
newSingleThreadExecutor():
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的 newFixedThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程(备注:应该是内部实现的差异 外部的使用没什么差异)。
因为一个任务执行完毕之后,线程才会空闲下来去执行另外一个任务,所以可以保证顺序执行任务。
测试ScheduledExecutorService
scheduled
adj. 预定的;已排程的
v. 把…列表;把…列入计划;安排(schedule的过去分词)
上面演示的线程执行器或者线程池都是ExecutorService,下面看看ScheduledExecutorService。ScheduledExecutorService集成并且扩展了ExecutorService,可安排在给定的延迟后运行或定期执行的命令。
package thread;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SingleThreadScheduledTest {
/**
* @author zjf
* @create_time 2013-12-23
* @use 测试SingleThreadScheduled线程池
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
ScheduledExecutorService es = Executors
.newSingleThreadScheduledExecutor();
//ScheduledThreadPool需要传参控制池中所保存的线程数(即使线程是空闲的也包括在内)
//ScheduledExecutorService es = Executors.newScheduledThreadPool(1);
// 给定时间延迟后执行
// es.schedule(new Countable(), 1, TimeUnit.SECONDS);
// 传入一个任务然后按照给定频率循环执行 在每次任务开始执行的时间点之间存在固定间隔
//es.scheduleAtFixedRate(new Countable(), 2, 1, TimeUnit.SECONDS);
// 传入一个任务然后按照给定频率循环执行 每一次执行终止和下一次执行开始之间都存在给定的间隔
es.scheduleWithFixedDelay(new Countable(), 2, 1, TimeUnit.SECONDS);
// 如果没有这句代码 将没有任何反应,因为----|
// 下面的shutdown代码将会阻止执行新加入任务 包含延迟执行而未执行的任务
TimeUnit.SECONDS.sleep(10);
es.shutdown();
}
static class Countable implements Runnable {
public void run() {
System.out.println("一个任务运行开始!");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
System.out.println("一个任务运行结束!");
}
}
}
package thread;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolTest {
/**
* @author zjf
* @create_time 2013-12-23
* @use 测试SingleThreadScheduled线程池
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
//ScheduledThreadPool需要传参控制池中所保存的线程数(即使线程是空闲的也包括在内)
ScheduledExecutorService es = Executors.newScheduledThreadPool(1);
es.scheduleAtFixedRate(new Countable(), 0, 1, TimeUnit.SECONDS);
TimeUnit.SECONDS.sleep(10);
es.shutdown();
}
static class Countable implements Runnable {
public void run() {
System.out.println("一个任务运行开始!");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
}
System.out.println("一个任务运行结束!");
}
}
}
/*
* 线程池中只有一个线程 + 每隔1秒要执行一个任务 + 一个任务要运行3秒才结束
* 结果是每隔3秒才能执行一次
*/
以上是关于Java编程思想 第21章 并发的主要内容,如果未能解决你的问题,请参考以下文章