线程下

10.4:线程互斥

在并发程序设计中已经被研究并得到解决.对多线程共享的资源或数据称为临界资源,而把每一个线程中访问临界资源的那一段代码称为临界代码.通过为临界带买段设置信号灯,就可以保证资源的完整性,从而安全地访问共享资源.

为了实现这种机制,Java语言提供了以下两方面的支持

为每个对象设置了一个互斥锁标记.该标记保证在任何时候,只能有一个线程有该互斥锁,其他线程如果需要获得互斥锁,必须等待当前拥有该锁的线程将其释放.该对象称为互斥对象.

为了配合使用对象的互斥锁,Java语言提供了保留字synchronized.其基本用法如下:

Synchronized(互斥对象){

临界代码

}

当一个线程执行到该行代码时,首先检测该互斥对象的互斥锁.如果该互斥锁没有被占用,则该线程将获得该互斥锁,并执行临界代码,直到执行完毕并释放互斥锁;

可以看出,任意一个对象都可以作为信息灯,从而解决上面的问题,首先定义一个互斥对象类,作为信号灯.由于该对象只作为信号量使用,所以并不需要为它定义其他方法.

public class AccountThread extends Thread

{

public static void main(String[] args)

{

Account account = new Account(100);

Semaphore semaphore = new Semaphore();

AccountThread at1 = new AccountThread(account, 1000, semaphore);

AccountThread at2 = new AccountThread(account, 0, semaphore);

at1.start();

at2.start();

}

Account account;

int delay;

Semaphore semaphore;

// 构造方法

public AccountThread(Account account, int delay, Semaphore semaphore)

{

this.account = account;

this.delay = delay;

this.semaphore = semaphore;

}

@Override

public void run()

{

synchronized (this.semaphore)

{

if (this.account.balance >= 100)

{

try

{

// 延迟

sleep(this.delay);

// 模拟取钱100

this.account.balance = this.account.balance - 100;

System.out.println("withdraw 100 successful!!!");

}

catch (InterruptedException e)

{

e.printStackTrace();

}

}

else

{

System.out.println("withdraw failed!!!");

}}}}

// 定义一个类,利用其对象作为互斥信号灯

class Semaphore{}

10.5:线程同步

在实际应用中,多个线程之间不仅需要互斥机制来保证对共享数据的完整性,而且有时需要多个线程之间的相互合作,一个典型的应用称为 生产者-消费者模型

1:生产者负责产品,并将其保存到仓库中

2:消费者从仓库中获取产品

3:由于库房容量有限,因此只有当库房还有空间时,生产者才可以将产品存入库房,否则只能等待

4:只有库房中存在满足数量的产品时,消费者才可以取走产品否则只能等待

Java语言为互斥对象提供了两个方法:一个是wait(),一个是notify() 这两个方法必须同时使用

wait()方法的语义是:当一个线程执行了该方法后,则该线程进入堵塞状态,同时让出同步对象的互斥锁,并自动进入互斥对象的等待队列

Notify()方法的语义是:当一个线程执行了该方法后,则拥有该方法的互斥对象的等待队列中的第一个线程被唤醒,同时自动获得该互斥对象的互斥锁,并进入就绪状态等待调度

10.6 线程通信

线程之间的通信问题是指线程之间互相传递信息,这些信息包括数据,控制指令.线程至之间通过管道进行通信

管道的特点?

1:管道是单向的.一个线程充当发送者,另一个线程充当接受者.如果需要建立双向通信,可以通过建立多个管道解决

2:管道通信是面向连接的.因此在程序设计中,一方线程必须建立起对应的端点,由另一方线程来建立连接.

3:官道中的通信是严格按照发送的顺序进行传送的.

10.7 线程死锁

线程死锁是并发程序设计中可能遇到的问题之一.它是指程序运行过程中,多个线程竞争共享资源时可能出现的一种系统状态.

出现线程死锁的必须同时具备的4个条件:

1:互斥条件.即至少存在一个资源,不能被多个线程同时共享.

2:至少存在一个线程,他拥有一个资源,并等待获得另一个线程当前锁拥有的资源.

3:线程拥有的资源不能被强制剥夺,只能由线程释放.

4:线程对资源的请求形成了一个圆环.

10.8 线程池

因为创建和清除线程垃圾都会大量占用CPU等系统资源,所以可以使用线程池来解决资源浪费的问题.

线程池的思想是:在系统中开辟一块区域,其中存放一些待命的线程,这个区域称为线程池,如果需要执行任务,则从线程池中一个待命的线程来执行指定的任务,等到任务结束可以再将所取的线程放回.这样就避免上面所说的问题.常用的线程池有 固定尺寸线程池和可变尺寸线程池,这种线程池中待命的数量是根据任务负载的需要动态变化的.

public class FixText implements Runnable

{

public static void main(String[] args)

{

// 创建尺寸为2的固定线程池

ExecutorService threadpool = Executors.newFixedThreadPool(2);

// 创建3个任务对象

FixText ft1 = new FixText("FT1");

FixText ft2 = new FixText("FT2");

FixText ft3 = new FixText("FT3");

// 启动三个任务执行

threadpool.execute(ft1);

threadpool.execute(ft2);

threadpool.execute(ft3);

threadpool.shutdown();

}

private String name;

public FixText(String name)

{

this.name = name;

}

public void run()

{

System.out.println("\n --------" + this.name + "开始执行");

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

{

System.out.print("[" + this.name + "]");

}

System.out.println("\n --------" + this.name + "执行结束");

}}

posted @ 2016-11-07 15:22  qingtianBKY  阅读(164)  评论(0编辑  收藏  举报