1.多进程:在操作系统中能(同时)运行多个任务(程序)
多线程:在同一应用程序中有多个顺序流(同时)执行
创建线程:通过java.lang.Thread来创建一个线程
启动线程:
v 每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。
v 使用start()方法,线程进入Runnable(可运行)状态,它将向线程调度器注册这个线程。
v 调用start()方法并不一定马上会执行这个线程,正如上面所说,它只是进入Runnable而不是Running。
v 注意,不要直接在程序中调用线程的run()方法。
2.Java中创建线程的两种方式:继承thread类;实现Runnable接口
**********两种创建方式,一种启动方式start*******
两种线程创建方式的比较
使用Runnable接口 RunnableDemo,RunnableTest
可以将CPU,代码和数据分开,形成清晰的模型;还可以从其他类继承;保持程序风格的一致性。
直接继承Thread类 ThreadDemo,Test
不能再从其他类继承;编写简单,可以直接操纵线程,无需使用Thread.currentThread()。
3.结束线程
v 线程会以以下三种方式之一结束:
§ 线程到达其 run() 方法的末尾;
§ 线程抛出一个未捕获到的 Exception 或 Error;
4.后台线程
有一种线程,它是在后台运行的,它的任务是为其他的线程提供服务,这种线程被称为"后台线程(Daemon Thread)",又称为"守护线程"
资源有限,排队,join
|
|
|
|
|
|
|
|
|
|
|
|
|
5.多线程编程
§ 多个线程来自同一个Runnable实例
§ 多个线程使用同样的数据和代码
在Java语言中,引入了对象互斥锁(mutual exclusive lock,也简称为对象锁)的概念,来保证共享数据操作的完整性:
§ 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
§ 关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。
关键字synchronized
v 在Java中的两种使用synchronized的方式:
§ 放在方法前面,这样,调用该方法的线程均将获得对象的锁。
§ 放在代码块前面,它也有两种形式:
• synchronized (this){… …}或synchronized {… …}:代码块中的代码将获得当前对象引用的锁
• synchronized(otherObj){… …}:代码块中的代码将获得指定对象引用的锁
释放锁
v 当线程执行到synchronized()块结束时,释放对象锁。
v 当在synchronized()块中遇到break, return或抛出exception,则自动释放对象锁。
v 当一个线程调用wait()方法时,它放弃拥有的对象锁并进入等待队列。
多线程编程一般规则
v 如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的,如果对象更新影响到只读方法,那么只读方法也要定义成同步的。
v 不要滥用同步。如果在一个对象内的不同的方法访问的不是同一个数据,就不要将方法设置为synchronized的。
v 如果一个线程必须等待一个对象状态发生变化,那么他应该在对象内部等待,而不是在外部。他可以通过调用一个被同步的方法,并让这个方法调用wait()。
v 每当一个方法返回某个对象的锁时,它应当调用notifyAll()来让等待队列中的其他线程有机会执行。
v 记住wait()和notify()/notifyAll()是Object类方法,而不是Thread类的方法。仔细查看每次调用wait()方法,都有相应的notify()/notifyAll()方法,且它们均作用于同一个对象。
生产者消费者例子
/**
* 仓库
* @author Administrator
*
*/
publicclass Godown
{
//总库存
privateintmax = 100;
//消费之后的库存数
privateintcurNum = 0;
public Godown()
{
}
public Godown(int _curNum)
{
this.curNum = _curNum;
}
/**
* 生产指定数量的产品
* @param needNum
*/
publicsynchronizedvoid produce(int needNum)
{
//如果需要生产的数量和当前结余的数量
//之和大于总库存,则暂停生产
while(needNum + curNum > max)
{
try
{
wait();
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
curNum += needNum;
System.out.println("已经生产了" + needNum + "个产品,现在仓库中有" + curNum + "个产品");
//唤醒消费者进行消费
notifyAll();
}
/**
* 消费产品
* @param consumNum 消费数
*/
publicsynchronizedvoid consume(int consumNum)
{
//不能消费时,则等待生产者生产产品
while(consumNum > curNum)
{
try
{
wait();
} catch (InterruptedException e)
{
// TODO Auto-generatedcatch block
e.printStackTrace();
}
}
curNum -= consumNum;
System.out.println("已经消费了" + consumNum + "个产品,现在仓库中有" + curNum + "个产品");
notifyAll();
}
}
/**
* 生产者
* @author Administrator
*
*/
publicclass Produce extends Thread
{
//仓库
private Godown gd = null;
//需要生产的数量
privateintneedNum;
public Produce(Godown _godown,int _needNum)
{
this.gd = _godown;
this.needNum = _needNum;
}
@Override
publicvoid run()
{
// TODO Auto-generatedmethod stub
// super.run();
//开始生产
gd.produce(needNum);
}
}
/**
* 消费者
* @author Administrator
*
*/
publicclass Consumer extends Thread
{
//仓库
private Godown gd = null;
//消费的数量
privateintconsumNum = 0;
public Consumer(Godown _gd,int _consumNum)
{
this.gd = _gd;
this.consumNum = _consumNum;
}
@Override
publicvoid run()
{
// TODO Auto-generatedmethod stub
// super.run();
gd.consume(consumNum);
}
}
publicclass Test
{
publicstaticvoid main(String[] args)
{
//初始库存10件产品
Godown gd = new Godown(10);
Produce pd = new Produce(gd,20);
pd.start();
Consumer cs = new Consumer(gd,60);
cs.start();
Produce pd2 = new Produce(gd,20);
pd2.start();
Produce pd3= new Produce(gd,20);
pd3.start();
}
}