java程序设计--孙鑫java无难事Lesson7《多线程》
1.程序、进程和线程程序: 程序是计算机指令的集合,它以文件的形式存储在磁盘上。
进程:是一个程序在其自身的地址空间中的一次执行活动。 进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占用系统的运行资源。
线程:是进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。
Java在语言级提供了对多线程程序设计的支持。
实现多线程程序的两种方式:
a.从Thread类继承
b.实现Runnable接口
(1)实现方式1从Thread类继承
测试代码如下:
- class MyThread extends Thread
- {
- MyThread(String name)
- {
- super(name);
- }
- public void run()
- {
- while(true)
- {
- System.out.println(getName());
- yield();//暂停线程运行
- }
- }
- }
- class MultiThread
- {
- public static void main(String[] args)
- {
- //从Thread类派生
- MyThread mt=new MyThread("Thread1");
- //mt.setDaemon(true);//标记为后台线程
- mt.setPriority(Thread.MAX_PRIORITY );//设置最高优先级
- mt.start();//启动线程
- int index=0;
- //当仅有后台线程运行时java虚拟机将退出
- while(true)
- {
- if(index++ == 100)
- break;//main方法退出
- System.out.println("main:"+Thread.currentThread().getName());
- }
- }
class MyThread extends Thread
{
MyThread(String name)
{
super(name);
}
public void run()
{
while(true)
{
System.out.println(getName());
yield();//暂停线程运行
}
}
}
class MultiThread
{
public static void main(String[] args)
{
//从Thread类派生
MyThread mt=new MyThread("Thread1");
//mt.setDaemon(true);//标记为后台线程
mt.setPriority(Thread.MAX_PRIORITY );//设置最高优先级
mt.start();//启动线程
int index=0;
//当仅有后台线程运行时java虚拟机将退出
while(true)
{
if(index++ == 100)
break;//main方法退出
System.out.println("main:"+Thread.currentThread().getName());
}
}
(2)实现方式2实现Runnable接口
测试代码如下:
//实现接口 允许继承类并且实现接口 同一资源的访问
- class MyThread implements Runnable
- {
- int index=0;//共享变量
- public void run()
- {
- while(true)
- {
- System.out.println(Thread.currentThread().getName()+index++);
- }
- }
- }
- class MultiThread
- {
- public static void main(String[] args)
- {
- MyThread mt=new MyThread( );
- new Thread(mt).start();//传递Runnable接口的实现类对象
- new Thread(mt).start();
- new Thread(mt).start();
- new Thread(mt).start();
- while(true)
- {
- System.out.println("main:"+Thread.currentThread().getName());
- }
- }
class MyThread implements Runnable
{
int index=0;//共享变量
public void run()
{
while(true)
{
System.out.println(Thread.currentThread().getName()+index++);
}
}
}
class MultiThread
{
public static void main(String[] args)
{
MyThread mt=new MyThread( );
new Thread(mt).start();//传递Runnable接口的实现类对象
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
while(true)
{
System.out.println("main:"+Thread.currentThread().getName());
}
}
运行过程中如下图所示:
测试代码如下:
- //利用内部类继承Thread
- class MyThread
- {
- int index=0;
- private class InnerThread extends Thread
- {
- public void run()
- {
- while(true)
- {
- System.out.println (Thread.currentThread().getName()+index++);
- }
- }
- }
- public Thread getThread()
- {
- return new InnerThread();
- }
- }
- class MultiThread
- {
- public static void main(String[] args)
- { MyThread mt=new MyThread();
- mt.getThread().start();
- mt.getThread().start();
- while(true)
- {
- System.out.println("main:"+Thread.currentThread().getName());
- }
- }
- }
//利用内部类继承Thread
class MyThread
{
int index=0;
private class InnerThread extends Thread
{
public void run()
{
while(true)
{
System.out.println (Thread.currentThread().getName()+index++);
}
}
}
public Thread getThread()
{
return new InnerThread();
}
}
class MultiThread
{
public static void main(String[] args)
{ MyThread mt=new MyThread();
mt.getThread().start();
mt.getThread().start();
while(true)
{
System.out.println("main:"+Thread.currentThread().getName());
}
}
}
3.线程的同步
同步的两种方式:同步块和同步方法
每一个对象都有一个监视器,或者叫做锁。
同步方法利用的是this所代表的对象的锁。静态方法的同步利用的该类的Class对象的监视器。每个class也有一个锁,是这个class所对应的Class对象的锁。
(1)线程未同步时出错:
测试代码如下:
- class SellThread implements Runnable
- {
- int tickets=1000;
- Object ob=new Object();
- public void run()
- {
- while(true)
- {
- //不加锁
- if(tickets>0)
- {
- try
- {
- Thread.sleep(5);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- new Thread(st).start();
- }
- }
class SellThread implements Runnable
{
int tickets=1000;
Object ob=new Object();
public void run()
{
while(true)
{
//不加锁
if(tickets>0)
{
try
{
Thread.sleep(5);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
new Thread(st).start();
}
}
//运行结果
Thread-0 Sell Tickets11
Thread-1 Sell Tickets10
Thread-0 Sell Tickets9
Thread-1 Sell Tickets8
Thread-0 Sell Tickets7
Thread-1 Sell Tickets6
Thread-0 Sell Tickets5
Thread-1 Sell Tickets4
Thread-0 Sell Tickets3
Thread-1 Sell Tickets2
Thread-0 Sell Tickets1
Thread-1 Sell Tickets0
(2)线程同步方法1--利用同步块
测试代码如下:
- class SellThread implements Runnable
- {
- int tickets=1000;
- Object ob=new Object();
- public void run()
- {
- while(true)
- { synchronized(ob)//同步块 对Object对象加锁
- {
- if(tickets>0)
- {
- try
- {
- Thread.sleep(5);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }//同步块执行完毕 解锁
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- new Thread(st).start();
- }
- }
class SellThread implements Runnable
{
int tickets=1000;
Object ob=new Object();
public void run()
{
while(true)
{ synchronized(ob)//同步块 对Object对象加锁
{
if(tickets>0)
{
try
{
Thread.sleep(5);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}//同步块执行完毕 解锁
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
new Thread(st).start();
}
}
同步块,运行结果如下图所示:
测试代码如下:
- class SellThread implements Runnable
- {
- int tickets=1000;
- Object ob=new Object();
- public void run()
- {
- while(true)
- {
- sell();//同步方法
- }
- }
- //synchronized关键字定义 同步方法 对this对象的监视器加锁
- public synchronized void sell()
- {
- if(tickets>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }//解锁this对象
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- new Thread(st).start();
- }
- }
class SellThread implements Runnable
{
int tickets=1000;
Object ob=new Object();
public void run()
{
while(true)
{
sell();//同步方法
}
}
//synchronized关键字定义 同步方法 对this对象的监视器加锁
public synchronized void sell()
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}//解锁this对象
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
new Thread(st).start();
}
}
同步方法,运行结果如下图所示:
验证代码如下:
- class SellThread implements Runnable
- {
- int tickets=500;//不同的数据可能线程的运行结果不一样
- Object obj=new Object();
- boolean b=false;
- public void run()
- {
- if(b==false)
- {
- while(true)
- {
- sell();
- }
- }
- else
- {
- while(true)
- {
- synchronized(obj) //同步obj对象则出错 同步this则正确
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- if(tickets>0)
- {
- System.out.println("Obj"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- }
- }
- }
- //同步方法 对this对象的监视器加锁
- public synchronized void sell()
- {
- if(tickets>0)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- System.out.println("Sell"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }//解锁this对象
- }
class SellThread implements Runnable
{
int tickets=500;//不同的数据可能线程的运行结果不一样
Object obj=new Object();
boolean b=false;
public void run()
{
if(b==false)
{
while(true)
{
sell();
}
}
else
{
while(true)
{
synchronized(obj) //同步obj对象则出错 同步this则正确
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
if(tickets>0)
{
System.out.println("Obj"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
}
}
}
//同步方法 对this对象的监视器加锁
public synchronized void sell()
{
if(tickets>0)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
System.out.println("Sell"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}//解锁this对象
}
当一个调用sell方法,一个利用Object对象同步时,出错,错误结果如下图所示:
当一个调用sell方法,另一个利用this对象同步时,结果正确,如下图所示:
死锁测试代码:
- //测试死锁
- class SellThread implements Runnable
- {
- int tickets=500;
- Object obj=new Object();
- boolean b=false;
- public void run()
- {
- if(b)
- {
- while(true)
- sell();
- }
- else
- {
- while(true)
- {
- //先同步obj对象 然后同步this对象
- synchronized(obj)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- synchronized(this)
- {
- if(tickets>0)
- {
- System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- }
- }
- }
- }
- //先同步this对象然后再同步obj对象
- public synchronized void sell()
- {
- synchronized(obj)
- {
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- if(tickets>0)
- {
- System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
- tickets--;
- }
- }
- }//解锁this对象
- }
- class TicketsSystem
- {
- public static void main(String[] args)
- {
- SellThread st=new SellThread();
- new Thread(st).start();
- try
- {
- Thread.sleep(10);
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- st.b=true;
- new Thread(st).start();
- }
- }
//测试死锁
class SellThread implements Runnable
{
int tickets=500;
Object obj=new Object();
boolean b=false;
public void run()
{
if(b)
{
while(true)
sell();
}
else
{
while(true)
{
//先同步obj对象 然后同步this对象
synchronized(obj)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
synchronized(this)
{
if(tickets>0)
{
System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
}
}
}
}
//先同步this对象然后再同步obj对象
public synchronized void sell()
{
synchronized(obj)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
if(tickets>0)
{
System.out.println("DeadLock"+Thread.currentThread().getName()+" Sell Tickets"+tickets);
tickets--;
}
}
}//解锁this对象
}
class TicketsSystem
{
public static void main(String[] args)
{
SellThread st=new SellThread();
new Thread(st).start();
try
{
Thread.sleep(10);
}
catch (Exception e)
{
System.out.println(e.toString());
}
st.b=true;
new Thread(st).start();
}
}
//运行结果如下:
DeadLockThread-0 Sell Tickets500
5.wait、notify、notifyAll
每一个对象除了有一个锁之外,还有一个等待队列(wait set),当一个对象刚创建的时候,它的等待队列是空的。
我们应该在当前线程锁住对象的锁后,去调用该对象的wait方法。
当调用对象的notify方法时,将从该对象的等待队列中删除一个任意选择的线程,这个线程将再次成为可运行的线程。当调用对象的notifyAll方法时,将从该对象的等待队列中删除所有等待的线程,这些线程将成为可运行的线程。
wait和notify主要用于producer-consumer这种关系中。(1)notify和wait方法需要在同步块中执行否则出错,错误信息如下:
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.IllegalM
onitorStateException
at java.lang.Object.notify(Native Method)
at Queue.get(Test.java:81)
at Consumer.run(Test.java:40)
java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at Queue.put(Test.java:55)
at Producer.run(Test.java:23)
同时注意wait方法需要捕获异常。
(2)消费者和生成者同步的模拟
测试代码如下:
- class Test
- {
- public static void main(String[] args)
- {
- Queue q=new Queue();
- Producer p=new Producer(q);
- Consumer c=new Consumer(q);
- p.start();
- c.start();
- }
- }
- class Producer extends Thread
- {
- Queue q;
- Producer(Queue q)
- {
- this.q=q;
- }
- public void run()
- {
- for(int i=0;i<10;i++)
- {
- q.put(i);
- System.out.println("Producer put "+i);
- }
- }
- }
- class Consumer extends Thread
- {
- Queue q;
- Consumer(Queue q)
- {
- this.q=q;
- }
- public void run()
- {
- while(true)
- {
- System.out.println("Consumer get "+q.get());
- }
- }
- }
- class Queue
- {
- int value=-1;
- boolean bfull=false;
- //注意同步块 wait和notify时必须对于同一个对象的队列
- public synchronized void put(int i)
- {
- //为空则放置数据
- if(!bfull)
- {
- value=i;
- bfull=true;
- notify();//通知等待的消费者
- }
- try
- {
- wait();
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- }
- public synchronized int get()
- {
- //为空则等待填充数据
- if(!bfull)
- {
- try
- {
- wait();
- }
- catch (Exception e)
- {
- System.out.println(e.toString());
- }
- }
- bfull=false;
- notify();//通知等待的生产者
- return value;
- }
- }
class Test
{
public static void main(String[] args)
{
Queue q=new Queue();
Producer p=new Producer(q);
Consumer c=new Consumer(q);
p.start();
c.start();
}
}
class Producer extends Thread
{
Queue q;
Producer(Queue q)
{
this.q=q;
}
public void run()
{
for(int i=0;i<10;i++)
{
q.put(i);
System.out.println("Producer put "+i);
}
}
}
class Consumer extends Thread
{
Queue q;
Consumer(Queue q)
{
this.q=q;
}
public void run()
{
while(true)
{
System.out.println("Consumer get "+q.get());
}
}
}
class Queue
{
int value=-1;
boolean bfull=false;
//注意同步块 wait和notify时必须对于同一个对象的队列
public synchronized void put(int i)
{
//为空则放置数据
if(!bfull)
{
value=i;
bfull=true;
notify();//通知等待的消费者
}
try
{
wait();
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
public synchronized int get()
{
//为空则等待填充数据
if(!bfull)
{
try
{
wait();
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
bfull=false;
notify();//通知等待的生产者
return value;
}
}
//运行结果(不知道为什么不是先打印Producer)
Consumer get 0
Producer put 0
Consumer get 1
Producer put 1
Consumer get 2
Producer put 2
Consumer get 3
Producer put 3
Consumer get 4
Producer put 4
Consumer get 5
Producer put 5
Consumer get 6
Producer put 6
Consumer get 7
Producer put 7
Consumer get 8
Producer put 8
Consumer get 9
Producer put 9
6.线程终止
设置一个flag变量并结合interrupt()方法。
测试代码如下:
- class TestThread
- {
- public static void main(String[] args)
- {
- Thread1 t1=new Thread1();
- t1.start();
- int index=0;
- while(true)
- {
- if(index++ == 500)
- {
- t1.stopThread();//调用后置停止运行标志为true
- t1.interrupt();//停止运行线程
- break;
- }
- System.out.println(Thread.currentThread().getName());
- }
- System.out.println("main exit!");
- }
- }
- class Thread1 extends Thread
- {
- private boolean bstop=false;
- public synchronized void run()
- {
- while(!bstop)
- {
- try
- {
- wait();//导致无法比较bstop 无法退出
- }
- catch (InterruptedException e)
- {
- //结合一个标志,在interrupt函数执行时判断标志,退出程序
- if(bstop)
- return;
- e.printStackTrace();
- }
- System.out.println(getName());
- }
- }
- public void stopThread()
- {
- bstop=true;//置停止运行标志为true
- }
- }
class TestThread
{
public static void main(String[] args)
{
Thread1 t1=new Thread1();
t1.start();
int index=0;
while(true)
{
if(index++ == 500)
{
t1.stopThread();//调用后置停止运行标志为true
t1.interrupt();//停止运行线程
break;
}
System.out.println(Thread.currentThread().getName());
}
System.out.println("main exit!");
}
}
class Thread1 extends Thread
{
private boolean bstop=false;
public synchronized void run()
{
while(!bstop)
{
try
{
wait();//导致无法比较bstop 无法退出
}
catch (InterruptedException e)
{
//结合一个标志,在interrupt函数执行时判断标志,退出程序
if(bstop)
return;
e.printStackTrace();
}
System.out.println(getName());
}
}
public void stopThread()
{
bstop=true;//置停止运行标志为true
}
}
//运行结果如下
main
main
main
main
main
main
main
main
main
main exit!
请按任意键继续. . .