多线程学习
* 程序,进程和线程
程序: 是指计算机指令的集合,它以文件的形式存储在磁盘上。
进程: 是一个程序在其自身的地址空间中的一次执行活动。
进程是资源的申请,调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请
系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不站用系统的运行资源。
线程: 是进程中一个单一的连接控制流程。一个进程可以有多个线程。
线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程
没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远
较进程简单。
* Java对多线程的支持
Java在语言级提供了对多线程程序设计的支持。
实现线程程序的两种方式:
(1)从Thread类继承;
(2)实现Runnable接口。
Java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪一个线程在
CPU上运行。
在java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的CPU时间的
进程)。抢占式调度模型就是许多线程处于可以运行状态(等待状态),但实际上只有一个线程在
运行。该线程一直运行到它终止进入可运行状态(等待状态),或者另一个具有更高优级的线程
变成可运行状态。在后一种情况下,低优先级的线程被高优先级的线程抢占,高优先级的线程获得
运行的机会。
Java线程调度器支持不同优先级线程的抢占方式,但其本身不支持相同优先级线程的时间片轮换。
Java运行时系统所在的操作系统(例如:windows2000)支持时间片的轮换,则线程调度器就支持
相同优先级线程的时间片轮换。
用多线程技术模拟一个售票系统
实现代码如下:
class TicketSystem
{
public static void main(String[] args)
{
SellTicket st = new SellTicket();
new Thread(st).start();
new Thread(st).start();
new Thread(st).start();
new Thread(st).start();
}
}
class SellTicket implements Runnable
{
int tickets=100;
Object o = new Object();
public void run()
{
while(true)
{
/*
synchronized(o) //同步块在关键字后得加个对象(任意的对象都可以)
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"sell tickets"+tickets);
tickets--;
}
}
*/
sell();
}
}
public synchronized void sell() //同步方法
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+
"sell tickets"+tickets);
tickets--;
}
}
}
* 线程的同步
The code segments within a program that access the same object from separate,concurrent
thread are called "critical sections"。
同步的两种方式:同步块和同步方法
没一个对象都有一个监视器(monitor),或者叫做琐。
同步方法利用的是this所代表的对象的琐。
每个class也有一个琐,是这个class所对应的Class对象的琐。
完整示例:
class TicketSystem
{
public static void main(String[] args)
{
SellTicket st = new SellTicket();
new Thread(st).start();
/*
*写一个try{}catch{}块让main()方法所在的线程睡1秒
*主要是想要线程优先启动
*/
try
{
Thread.sleep(1);
}
catch(Exception e)
{
e.printStackTrace();
}
st.b=true;
new Thread(st).start();
//new Thread(st).start();
//new Thread(st).start();
}
}
class SellTicket implements Runnable
{
int tickets=100;
Object obj = new Object();
boolean b=false;
public void run()
{
if(b==false)
{
while(true)
sell();
}
else
{
while(true)
{
synchronized(this) //同步块在关键字后得加个对象(任意的对象都可以)
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("obj:"+Thread.currentThread().getName()+
" sell tickets"+tickets);
tickets--;
}
}
// sell();
}
}
}
public synchronized void sell() //同步方法
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("sell():"+Thread.currentThread().getName()+
"sell tickets"+tickets);
tickets--;
}
}
}
* 线程的死琐
哲学家进餐的问题
一帮哲学家在一起进餐,但是每个人都只有1支筷子,大家都在等待别人拿出一支筷子让自己
先吃,然后再把自己的拿出去,但是大家都不愿意拿出自己的筷子。
线程1琐住了对象A的监视器,等待对象B的监视器,线程2锁住了对象B的监视器,等待对象A的
监视器,就造成了死琐。
示例代码:
class TicketSystem
{
public static void main(String[] args)
{
SellTicket st = new SellTicket();
new Thread(st).start();
/*
*写一个try{}catch{}块让main()方法所在的线程睡1秒
*主要是想要线程优先启动
*/
try
{
Thread.sleep(1);
}
catch(Exception e)
{
e.printStackTrace();
}
st.b=true;
new Thread(st).start();
//new Thread(st).start();
//new Thread(st).start();
}
}
class SellTicket implements Runnable
{
int tickets=100;
Object obj = new Object();
boolean b=false;
public void run()
{
if(b==false)
{
while(true)
sell();
}
else
{
while(true)
{
synchronized(obj) //同步块在关键字后得加个对象(任意的对象都可以)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
synchronized(this)
{
if(tickets>0)
{
System.out.println("obj:"+Thread.currentThread().getName()+
" sell tickets"+tickets);
tickets--;
}
}
}
}
}
}
public synchronized void sell() //同步方法
{
synchronized(obj)
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("sell():"+Thread.currentThread().getName()+
"sell tickets"+tickets);
tickets--;
}
}
}
}
* wait,notify,notifyAll
每个对象除了有一个琐之外,还有一个等待队列(wait set),当一个对象刚刚创建的时候,它
的等待队列是空的。
我们应该在当前线程锁住对象的琐后,去调用该对象的wait方法。
当调用对象的notify方法时,将从该对象的等待队列中删除一个任意的线程,这个线程将再次
成为可运行的线程。
当调用对象的notifyAll方法时,将从该对象的等待队列中删除所有等待的线程,这些线程将
成为可运行的线程。
wait和notify重要用于producer-consumer这种关系中。
代码示例:
class Test
{
public static void main(String[] args)
{
Queque q = new Queque();
Procedur p = new Procedur(q);
Consumer c = new Consumer(q);
p.start();
c.start();
}
}
class Procedur extends Thread //生产者
{
Queque q;
Procedur(Queque q)
{
this.q=q;
}
public void run()
{
for(int i=0;i<10;i++)
{
q.put(i);
System.out.println("Procedur put"+ i);
}
}
}
class Consumer extends Thread //消费者
{
Queque q;
Consumer(Queque q)
{
this.q=q;
}
public void run()
{
while(true)
{
System.out.println("Consumer get"+q.get());
}
}
}
class Queque //放置数据
{
int value;
boolean bFull=false;
public synchronized void put(int i)
{
if(!bFull)
{
value=i;
bFull=true;
notify();
}
try
{
wait();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public synchronized int get()
{
if(!bFull)
{
try
{
wait();
}
catch(Exception e)
{
e.printStackTrace();
}
}
bFull=false;
notify();
return value;
}
}
线程的状态图
|
| new Thread
| yield sleep,wait,suspend,I/O阻塞
\|/ start |------------------------------------>|
New----->Runnable| |Not Runnable
\ |<------------------------------------| /
\ sleep结束,notify,resume,I/O操作完成 /
\ /
\ /
\ /
\ /
\ run方法退出 /
\stop方法调用 /
\ /
\ /
\ / stop方法调用
\ /
\ /
\ /
\ /
\ /
\ /
\ ______ _____/
| Dead |
|____________|
线程的终止
设置一个flag变量。
结合interrupt()方法。
code:
class TestThread
{
public static void main(String[] args)
{
Thread1 t1=new Thread1();
t1.start();
int index=0;
while(true)
{
if(index++==500)
{
t1.stopThread();
break;
}
System.out.println(Thread.currentThread().getName());
}
}
}
class Thread1 extends Thread
{
private boolean bStop=false;
public void run()
{
while(!bStop)
{
System.out.println(getName());
}
}
public void stopThread()
{
bStop=true;
}
}