您的位置:首页 > 其它

多线程知识点3

2015-06-22 13:41 253 查看
如果对一块共享数据,多个线程做不同的操作,有读有写,就有必要进行线程通讯处理,以便提高效率。

一、线程通讯:

1、线程通讯的概念:

线程通讯指的是多个线程通过消息传递实现相互牵制,相互调度,即线程间的相互作用。

2、Java线程通讯的实现:

Java代码中基于对共享数据进行“wait()、notify()、notifyAll()”来实现多个线程的通讯。

经典例子:生产者和消费者的问题。

1)、Warehouse.java

<span style="font-size:18px;">import java.util.ArrayList;
import java.util.List;

/**
* 仓库类,用储存商品,联系生产者和消费者
* @author hanwen
*
*/
public class Warehouse {

//定义一个集合,用来存储生产的产品
private List<String> products=new ArrayList<String>();

/**
* 生产者生产商品,存储到仓库里
*/
public void addproduct(String stringname){
products.add(stringname);//想仓库里面添加产品
}

/**
* 消费者消费商品
*/
public String getProduct(){
//判断仓库是不是为空
if(!products.isEmpty()){
//从仓库中取产品,返回给消费者
String stringname=products.remove(0);
return stringname;
}else{
System.out.println("仓库为空,请及时生产产品...");
return "";
}
}

/**
* 获取库存余量
*
* @return
*/
public int getSize(){
//返回库存余量
return products.size();
}
}</span>


2)、CustomerThread.java

<span style="font-size:18px;">/**
* 消费者线程类
*
* @author Administrator
*
*/
public class CustomerThread implements Runnable {
// 属性
private Warehouse wh;      // 仓库对象
private String name;       // 消费者姓名

// 构造函数传递参数
public CustomerThread(Warehouse wh, String name) {
super();
this.wh = wh;
this.name = name;
}

// 消费产品
@Override
public void run() {

while (true) {
synchronized (wh) {
if (wh.getSize() == 0) {
try {
System.out.println("仓库为空,消费者" + name + "进入等待状态........");
wh.wait();
System.out.println("线程等待结束,重新启动");

} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (wh.getSize() > 0) {
// 取走商品,
String stringname = wh.getProduct();
System.out.println("消费者" + name + "取走了产品" + stringname);
}
}
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}</span>


3)、ProductThread.java

<span style="font-size:18px;">import java.util.Random;

public class ProductThread implements Runnable {

// 定义一个仓库对象
private Warehouse wh;

// 有参数的构造方法
public ProductThread(Warehouse wh) {

super();
this.wh = wh;
}

/**
* 开始生产产品
*/
@Override
public void run() {
while (true) {
// 自动的随机产生产品
String stringname = "p" + (new Random()).nextInt(1000);

synchronized (wh) {
// 把产品放进仓库
wh.addproduct(stringname);
// 提示信息
System.out.println("仓库里面已经存入商品" + stringname);
//唤醒线程,让他继续执行
//wh.notify();
wh.notifyAll();
}
try {
// 睡一会
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}</span>


4)、TestDemo.java

<span style="font-size:18px;">/**
* 测试类
* @author Administrator
*
*/
public class TestDemo {

public static void main(String[] args) {

//实例化仓库对象
Warehouse wh=new Warehouse();

//实例化生产者对象
ProductThread pt=new ProductThread(wh);
//实例化消费者对象
CustomerThread ct=new CustomerThread(wh,"小明");
CustomerThread ct1=new CustomerThread(wh,"小花");
CustomerThread ct2=new CustomerThread(wh,"小灰灰");
CustomerThread ct3=new CustomerThread(wh,"小飞飞");

//建线程类进行包装
Thread t=new Thread(pt);
Thread t2=new Thread(ct);
Thread t3=new Thread(ct1);
Thread t4=new Thread(ct2);
Thread t5=new Thread(ct3);

//启动线程
t.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}</span>


3、wait()、notify()、notifyAll() 方法:

①、final void notify() 唤醒在此对象监视器上等待的单个线程

②、final void notifyAll() 唤醒在此对象监视器上等待的所有线程

③、final void wait() throws InterruptedException 导致当前的线程等待,直到其他线程调用此对象的 notify()

方法或 notifyAll() 方法

④、final void wait(long timeout) throws InterruptedException 导致当前的线程等待,直到其他线程调用此对

象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。

⑤、final void wait(long timeout, int nanos) throws InterruptedException 导致当前的线程等待,直到其他

线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实

际时间量。

⑥、wait() 和 notify() 方法(包括上述的所有方法,下同) 都是 Object 类的最终方法,所以每个类默认都拥有该方 法。为确保 wait() 和 notify() 的功能,在执行之前必须要先获得互斥锁,即一定要和 synchronized 一起使用。

如 synchronized 的锁对象是 obj 的话,wait 和 notify 正确的使用方法是obj.wait()和obj.notify()。

4、sleep() 和 wait() 的区别:

sleep()
wait()

属性 Thread的静态方法 Object的方法

作用
让本线程进入睡眠状态 让本线程进入等待状态

是否释放同步锁 不会释放同步所 会释放同步所

5、线程死锁:

①、线程死锁指的两个线程互相持有对方依赖的共享资源,造成都无限阻塞。

②、导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。

③、解决死锁的方法:

让线程持有独立的资源。

尽量不采用嵌套的 synchronized 语句。

6、线程状态转换:

线程状态介绍

1)、新建状态(New):使用 new 关键字创建线程对象,仅仅被分配了内存;

2)、可运行状态(Runnable):线程具备获得CPU时间片的能力。线程进入可运行状态的情况如下:

①、线程 start() 方法被调用;

②、当前线程 sleep()、其它线程 join() 结束、等待用户输入完毕;

③、某个线程取得对象锁;

④、当前线程时间片用完了,调用当前线程的 yield() 方法。

3)、运行状态(Running):执行 run 方法,此时线程获得CPU的时间片;

4)、阻塞状态(Blocked):线程由于某些事件放弃CPU使用权,暂停运行。直到线程重新进入可运行

状态,才有机会转到运行状态。阻塞状态分为如下几种:

①、同步阻塞 – 线程获得同步锁,若被别的线程占用,线程放入锁池队列中。

②、等待阻塞 – 线程执行 wait() 方法,线程放入等待队列中。

③、其它阻塞 – 线程执行 sleep() 或 join() 或发出 I/O 请求。

5)、死亡状态(Dead):run、main() 方法执行结束,或者因异常退出了 run() 方法,线程进入死亡状

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