您的位置:首页 > 其它

线程复习笔记

2012-03-31 10:05 197 查看
1 线程的三种方式:

A 实现Runnable接口 new Thread(new MyRunnable()).start();

B 继承Thread类

C Callable与Future方式

2 中断线程

interrupt方法请求终止线程(线程的中断状态被置位)

isInterrupted方法,检查这个中断状态

while( !Thread.currentThread().isInterrupted() ) { do more work!}

注:有个静态方法interrupted,也是用来测试当前线程是否被中断,但是这一方法会产 生副作用--他将当前现在的中断状态置为false.

3 线程的六种状态:

new(新生)、runnable(可运行)、blocked(阻塞)、

waitng(等待)、timed waiting(计时等待)、terminated(终止)

当一个线程视图获取一个内部的对象锁,而该锁被其他线程持有,则该线程进入阻塞状态。当线程等待另一个线程通知调度时,他自己进入等待状态。如调用Object.wait或者

Thread.join

4 wait和sleep区别

a:sleep() 方法是使线程停止运行一段时间,sleep时间间隔期满后,线程不一定立即恢 复运行。

wait()是线程交互式,如果线程对一个同步对象(方法)发出一个wait调用,改线程会暂停执行,被调用对象(方法)进入等待状态,直到被唤醒。

b:Sleep时别的线程也不可以访问锁定对象(睡着也抱着锁);

Wait时别的线程可以访问锁定对象(调用wait,锁就撒手);

5 锁

a:synchronized 如:public synchronized void push(char c);

b:java.util.concurrent.locks.ReentrantLock类,

ReentrantLock(boolean fair)

这个构造方法还可以创建一个带有公平策略的锁。公平锁偏爱等待时间最长的线程。但是,这一公平的保证将大大降低性能。

注:如果线程调度器选择忽略一个线程,而该线程为了这个锁已经等待很长时间了,哪么也没有几乎公平处理这个锁。

class X {

private final ReentrantLock lock = new ReentrantLock();

public void m() {

lock.lock(); // block until condition holds

try {

// ... method body

} finally {

lock.unlock()

}

}

}

补充volatile关键字

有时候为了读写一两个实例域就使用同步,显然开销会很大。这里推荐使用volatile关键字。

private boolean done;

public synchronized boolean getDone(){return done;}

public synchronized void setDone(boolean done) {this.done = done;}

相当于:

private volatile boolean done;

public boolean getDone(){return done;}

public void setDone(boolean done) {this.done = done;}

6 新的锁控制和应用例子

class Bank

{

private Lock bankLock;

private Condition sFouds;

public Bank()

{

bankLock = new ReenTrantLock();

sFouds = bankLock.newCondition();//条件叫余额充足

}

public void transfer()

{

backLock.lock();

while(acounts[forms] < amount)

{

sFouds.await();

}

//do more work

sFouds.signalAll();

}

}

7.内部的锁和条件存在一些局限(synchronized)

a不能中断一个正在试图获得锁的线程。

b视图获得锁时不能设定超时。

c每个锁仅有单一条件,可能不够。

8.特殊锁

synchronized(obj) { ... }

使用一个对象的锁定来实现额外的原子操作,称为客户端锁定。client-side locking

客户端锁定非常脆弱,通常不推荐使用。

9.读写锁

java.util.concurrent.locks.ReentrantReadWriteLock类

如果很多线程从一个数据结构读取数据,而很少线程修改其中的数据的话,此类非常有用。

private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

private Lock readLock = rwl.readLock();

private Lock writeLock = rwl.writeLock();

public doble getTBalance()

{

readLock.lock();

try { ... }

finally {readLock.unlock();}

}

public void transfer()

{

writeLock.lock();

try { ... }

finally {writeLock.unlock();}

}

10.死锁

public class DeadLock extends Thread {

int flag=0;

static Object o1=new Object();

static Object o2=new Object();

public DeadLock(int flag){

this.flag=flag;

}

@Override

public void run() {

if(this.flag==1){

synchronized(o1){

System.out.println(Thread.currentThread().getName()+"锁定对象o1");

try {

Thread.sleep(1000);//让另一个线程能进入另一块区域,锁定对象o2

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(o2){

System.out.print("this.flag="+this.flag);

}

}

}

if(this.flag==2){

synchronized(o2){

System.out.println(Thread.currentThread().getName()+"锁定对象o2");

try {

Thread.sleep(1000);//让另一个线程能进入另一块区域,锁定对象o1

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized(o1){

System.out.print("this.flag="+this.flag);

}

}

}

}

public static void main(String []args){

DeadLock d1=new DeadLock(1);

DeadLock d2=new DeadLock(2);

d1.start();

d2.start();

}

}

11.经典生产者与消费者

class SyncStack{

private int index = 0;

private char []data = new char[6];

public synchronized void push(char c){

if(index == data.length){

try{

this.wait();

}catch(InterruptedException e){}

}

this.notify();

data[index] = c;

index++;

}

public synchronized char pop(){

if(index ==0){

try{

this.wait();

}catch(InterruptedException e){}

}

this.notify();

index--;

return data[index];

}

}

class Producer implements Runnable{

SyncStack stack;

public Producer(SyncStack s){

stack = s;

}

public void run(){

for(int i=0; i<20; i++){

char c =(char)(Math.random()*26+'A');//

stack.push(c);

System.out.println("produced:"+c);

Thread.sleep((int)(Math.random()*1000));

}

}

}

class Consumer implements Runnable{

SyncStack stack;

public Consumer(SyncStack s){

stack = s;

}

public void run(){

for(int i=0;i<20;i++){

char c = stack.pop();

System.out.println("消费:"+c);

Thread.sleep((int)(Math.random()*1000));

}

}

}

public class ProduceConsumer {

public static void main(String args[]){

SyncStack stack = new SyncStack();

Runnable p=new Producer(stack);

Runnable c = new Consumer(stack);

Thread t1 = new Thread(p);

Thread t2 = new Thread(c);

t1.start();

t2.start();

}

}

12 阻塞队列

阻塞队列方法分3类,取决与队列满时或空时他们的响应方式,

如果将队列当做线程管理工具来使用,将要使用put和take方法,满或空,线程阻塞。

add、 element 、remove和操作抛出异常。

在一个多线程程序中,队列会在任何时候空或者满,offer、poll、peek,这些方法有返回值。

java.util.concurrent包提供了阻塞队列的几个变种

LinkedBlockingQueue 容量默认为int的最大值,也可以指定最大容量。

LinkedBlockingDeque 是一个双端版本。

ArrayBlockingQueue 在构造时需指定容量,并且有个可选的参数来指定是否需要公平性。若设置了公平参数,则等待最长时间的线程会优先处理,

这一设置会降低性能。

PriorityBlockingQueue 带优先级的队列

13 Callable与Future

Runable封装的一个异步运行的任务,可以把它想象成一个没有参数和返回值的异步方法。

Callable与Runnable类似,但是有返回值。Future保存异步计算的记过,get方法调用被阻塞,直到计算完成。

FutureTask包装器是一种非常便利的机制,可将Callable接口转换成Future和Runable,它同时实现二者接口。

例如:

Callable<Integer> myComputation = ...;

FutureTask<Integer> task = new FutureTask<Integer>(myComputation)

new Thread(task).start();

Integer result = task.get();

例如:

class MatchCounter implements Callable<Integer>

{

private File startDir;

private String keyword;

private int count;

public MatchCounter(File startDir,String keyword)

{

this.startDir = startDir;

this.keyword = keyword;

}

@Override

public Integer call() throws Exception

{

count = 0;

File[] files = startDir.listFiles();

ArrayList<Future<Integer>> results = new ArrayList<Future<Integer>>();

for(File f: files) {

if(f.isDirectory()){

MatchCounter counter = new MatchCounter(f,keyword);

FutureTask<Integer> task = new FutureTask<Integer>(counter);

results.add(task);

new Thread(task).start();

} else{

if(search(f)){

count ++;

}

}

}

for(Future<Integer> result : results)

{

count += result.get();

}

return count;

}

public boolean search(File file) {

boolean flag = false;

try

{

Scanner in = new Scanner(file);

while(in.hasNextLine() && !flag)

{

String str = in.nextLine();

if(str.contains(keyword))

{

flag = true;

}

}

in.close();

}

catch (FileNotFoundException e)

{

e.printStackTrace();

}

return flag;

}

}

14 执行器Executor

使用线程池理由:

a:线程池包含许多空闲线程,当一线程退出时,线程不会死亡,而是在池中准备为下一请求提供服务。

b:使用线程池可以减少并发线程的数目。(创建固定线程数的线程池)

Executors类有许多静态工厂方法用来构建线程池,如:

newCachedThreadPool 必要时创建新线程;空闲线程会被保留60秒

newFuxedThreadPool 该池包含固定数量的线程;空闲线程一致被保留

newSingleThreadExecutor 只有一个线程的池,该线程顺序执行每一个提交的任务

newScheduledThreadPool 用于预定执行而构建的固定线程池,替代java.util.Timer

newSingleThreadScheduledExecutor 用于预定执行而构建的单线程池。

使用线程池应该做的事:

1)调用Executors类中的静态方法产生线程池。

2)调用submit提交Runable或Callable对象,该方法返回值为Future对象。

3)如果想要取消一个任务,或如果提交Callable对象,那就要保存好返回的Future对象。

4)当不再提交任务时,调用shutdown。

ExecutorService pool = Executors.newCachedThreadPool();

MatchCounter counter = new MathcCounter(...);

Futurn<Integer> countResult = pool.submit(counter);

ExecutorService接口常用方法

invokeAll 执行给定的任务,当所有任务完成时,返回保持任务结果的 Future 列表

List<Callable<T>> tasks = ...?;

List<Future<T>> results = executorService.invokeAll(tasks);

invokeAny 执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。

<T> T invokeAny(Collection<? extends Callable<T>> tasks)

shutdown 启动线程依此顺序关闭,执行以前提交的任务,但不接受新任务

List<Runnable> shutdownNow() 试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。

submit 提交一个任务。

15 预定执行

ScheduleExecutorService接口具有为预定执行(Scheduled Execution)或重复执行而设计的方法。

Executors类的newScheduledThreadPool 和newSingleThreadScheduledExecutor方法返回实现了ScheduledExecutorService接口的对象。

java.util.concurrent.ScheduledExecutorService:

ScheduledFuture<?> schedule(Runnable command, long delay,TimeUnit unit) 预定在指定的时间之后执行

ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

command - 要执行的任务

initialDelay - 首次执行的延迟时间

period - 连续执行之间的周期

unit - initialDelay 和 period 参数的时间单位

16 门闩java.util.concurrent.CountDownLatch

CountDownLatch

一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

await() 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。

await(long timeout, TimeUnit unit) 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。

countDown() 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。

CountDownLatch 很适合用来将一个任务分为n个独立的部分,等这些部分都完成后继续接下来的任务,CountDownLatch 只能出发一次,计数值不能被重置。

例:一个项目可以分为多个模块,只有但这些模块都完成后才可以继续下一步的工作。

class Module implements Callable<Integer>

{

private CountDownLatch latch;

private String moduleName;

private int time;

public Module(CountDownLatch latch, String moduleName, int time)

{

this.latch = latch;

this.moduleName = moduleName;

this.time = time;

}

private void work() throws InterruptedException

{

TimeUnit.MILLISECONDS.sleep(time);

System.out.println(moduleName + " 完成,耗时:" + time);

}

@Override

public Integer call() throws Exception

{

work();

latch.countDown();

return time;

}

}

class Controller implements Runnable

{

private CountDownLatch latch;

private List<Future<?>> runResults;

int count = 0;

public Controller(CountDownLatch latch,List<Future<?>> runResults)

{

this.latch = latch;

this.runResults = runResults;

}

@Override

public void run()

{

latch.await();

for(Future<?> f : runResults)

{

count = count + (Integer)f.get();

}

System.out.println("所有模块都完成,耗时:" + count);

}

}

public class Project

{

static final int SIZE = 20;

public static void main(String[] args) throws InterruptedException, ExecutionException

{

List<Future<?>> runResults = new ArrayList<Future<?>>();

CountDownLatch latch = new CountDownLatch(SIZE);

ExecutorService exec = Executors.newCachedThreadPool();

for (int i = 0; i < SIZE; i++)

{

Future temp = exec.submit(new Module(latch, "模块" + (i + 1), (i + 1)));

runResults.add(temp);

}

Controller controller = new Controller(latch,runResults);

exec.submit(controller);

exec.shutdown();

}

}

17 栅栏java.util.concurrent.CyclicBarrier

一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point),线程才继续开始执行任务.

在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该barrier在释放等待线程后可以重用,

所以称它为循环的barrier。CyclicBarrier可以多次重复使用.

await() 在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待

await(long timeout, TimeUnit unit) 在所有参与者都已经在此屏障上调用 await 方法之前将一直等待,或者超出了指定的等待时间。

3个玩家同时进行通关游戏,当他们都到达或通过某一关后,才可继续往下过关.

class GameGate

{

// 关名称

private String barrierName;

// 玩家通关时间

private int passTime;

public GameGate(String barrierName, int passTime)

{

this.barrierName = barrierName;

this.passTime = passTime;

}

public String getBarrierName()

{

return barrierName;

}

public int getPassTime()

{

return passTime;

}

}

class GameRunable implements Runnable

{

// 游戏关集合

private List<GameGate> gameGates;

// 玩家名称

private String gamePlayer;

private CyclicBarrier cyclicBarrier;

public GameRunable(List<GameGate> gameGates, String gamePlayer,CyclicBarrier cyclicBarrier)

{

this.cyclicBarrier = cyclicBarrier;

this.gameGates = gameGates;

this.gamePlayer = gamePlayer;

}

public void run()

{

try

{

for (GameGate gameBarrier : gameGates)

{

Thread.sleep(gameBarrier.getPassTime() * 1000);

System.out.println(gamePlayer + " passed game barrier " + gameBarrier.getBarrierName());

cyclicBarrier.await();

}

}

}

public static void main(String[] args) {

CyclicBarrier barrier = new CyclicBarrier(3);

// 为玩家1建立通关任务

List<GameGate> playerOneGates = new ArrayList<GameGate>(4);

playerOneGates.add(new GameGate("第一关", 5));

playerOneGates.add(new GameGate("第二关", 60));

playerOneGates.add(new GameGate("第三关", 8));

GameRunable task1 = new GameRunable(playerOneGates, "张三", barrier);

// 为玩家2建立通关任务

List<GameGate> playerTwoGates = new ArrayList<GameGate>(4);

playerTwoGates.add(new GameGate("第一关", 1));

playerTwoGates.add(new GameGate("第二关", 6));

playerTwoGates.add(new GameGate("第三关", 3));

GameRunable task2 = new GameRunable(playerTwoGates, "李四", barrier);

// 为玩家3建立通关任务

List<GameGate> playerThreeGates = new ArrayList<GameGate>(4);

playerThreeGates.add(new GameGate("第一关", 7));

playerThreeGates.add(new GameGate("第二关", 6));

playerThreeGates.add(new GameGate("第三关", 4));

GameRunable task3 = new GameRunable(playerThreeGates, "王五", barrier);

ExecutorService executorService = Executors.newFixedThreadPool(3);

executorService.submit(task1);

executorService.submit(task2);

executorService.submit(task3);

executorService.shutdown();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: