对于单cpu电脑,它会时分复用的执行系统中的多个进程,而每个进程中也会有多个线程。
练习1:程序在没有采取多线程技术时,默认单线程执行
练习2:程序添加多线程技术以后,类ThreadDemo继承多线程类Thread,实现其run方法。
class ThreadDemol
{
public static void main(String [] args)
{
new ThreadDemo().start();//run();
while(true)
{
System.out.println("main()"+Thread.currentThread().getName());
}
}
}
class ThreadDemo extends Thread
{
public void run()
{
while(true)
{
System.out.println("run()"+Thread.currentThread().getName());
}
}
}
练习3:后台线程与联合线程
1) 只要还有一个前台线程运行,进程就不会结束。
2) 加入后台线程,进程会很快结束
3) Thread tt=new ThreadDemo();
tt.setDaemon(true);
tt.start();
4) join()进行线程联合
Thread tt=new ThreadDemo();
tt.start();
int index=0;
while(true)
{
if(index++==100)
try{tt.join();}catch(Exception e){}
System.out.println("main()"+Thread.currentThread().getName());
}
总结:刚开始两个线程交替执行,在主线程执行100次之后,调用tt线程的join方法,只执行tt线程
try{tt.join(5000);}catch(Exception e){}
总结:在join中添加时间,在tt线程执行5秒之后,又开始两个线程交替运行。
练习4:Thread类的构造方法,用Runnable接口实现多线程
1) 通过继承的方法实现多线程卖票
new ThreadDemo().start();
new ThreadDemo().start();
new ThreadDemo().start();
new ThreadDemo().start();
总结:构建了4个卖票的对象线程,分别卖100张票
2) 通过接口的方法实现多线程卖票
ThreadDemo tt=new ThreadDemo();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
总结:一般多线程都有接口实现,用起来较灵活,一个类可以有多个接口。
练习5:多线程的应用
1) 聊天时可以同时执行收发数据的程序
2) 一个循环执行的程序,可以用多线程控制
练习6:多线程的同步—多线程的控制
1) synchronized(str)监视器
在需要线程保护的代码块加入synchronized,将str设置为全局变量,当某一线程开始执行时,str的标志位从1变为0,执行结束时str’标志从0变为1当其他的线程想加入时会判断str的状态,如果str为0则不能加入,这达到了对某个程序块完整执行的保护。
2) 代码块和函数同步
在代码块上加入this对象,使代码块和函数公用一个对象进行监视。
3) 死锁
当两个呈现原子性的代码块并行运行时,一个代码块在运行时调用另外一个代码块的锁的状态,该代码块将被锁住
(1.34分)
练习7:使用多线程进行通信
原始代码:
class Producer implements Runnable
{
Q q;
public Producer(Q q)
{
this.q=q;
}
public void run()
{
int i=0;
while(true)
{
synchronized(q)
{
if(q.bFull)
try{q.wait();}catch(Exception e){};
if(i==0)
{
q.name="zhangsan";
try{Thread.sleep(1);}catch(Exception e){}
q.sex="male";
}else
{
q.name="lisi";
q.sex="female";
}
q.bFull=true;
q.notify();
}
i=(i+1)%2;
}
}
}
class Consumer implements Runnable
{
Q q;
public Consumer(Q q)
{
this.q=q;
}
public void run()
{
while(true)
{
synchronized(q)
{
if(!q.bFull)
try{q.wait();}catch(Exception e){};
System.out.print(q.name);
System.out.println(":"+q.sex);
q.bFull=false;
q.notify();
}
}
}
}
class Q
{
String name="unknow";
String sex="unknow";
boolean bFull=false;
}
class ThreadCommunation
{
public static void main(String args[])
{
Q q=new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
代码精简后:
class Producer implements Runnable
{
Q q;
public Producer(Q q)
{
this.q=q;
}
public void run()
{
int i=0;
while(true)
{
if(i==0)
{
q.set("zhangsan","male");
}else
{
q.set("lisi","female");
}
i=(i+1)%2;
}
}
}
class Consumer implements Runnable
{
Q q;
public Consumer(Q q)
{
this.q=q;
}
public void run()
{
while(true)
{
q.get();
}
}
}
class Q
{
String name="unknow";
String sex="unknow";
boolean bFull=false;
public synchronized void set(String name,String sex)
{
if(bFull)
try{wait();}catch(Exception e){};
this.name=name;
try{Thread.sleep(1);}catch(Exception e){}
this.sex=sex;
bFull=true;
notify();
}
public synchronized void get()
{
if(!bFull)
try{wait();}catch(Exception e){};
System.out.print(name);
System.out.println(":"+sex);
bFull=false;
notify();
}
}
class ThreadCommunation
{
public static void main(String args[])
{
Q q=new Q();
new Thread(new Producer(q)).start();
new Thread(new Consumer(q)).start();
}
}
总结:使在缓存中填入数据和在缓存中读取数据具有原子性,这样就不会在读取姓名zhangsan时,又被中断而读取性别是female,而实现同步。使用wait和notify进行流程控制,使数据放入之后再取,数据取出时再放,使通信更加有效。
练习8:线程控制
源代码:
class ThreadCommunation
{
public static void main(String args[])
{
ThreadTest t=new ThreadTest();
Thread tt=new Thread(t);
tt.start();
for(int i=0;i<100;i++)
{
if(i==50)
t.stopMe();
System.out.println("main() is running");
}
}
}
class ThreadTest implements Runnable
{
private boolean bStop=false;
public void stopMe()
{
bStop=true;
}
public void run()
{
while(!bStop)
{
System.out.println(Thread.currentThread().getName()+"is runnting");
}
}
}
总结:在某个线程上的程序运行结束时,线程自动释放,通过编写代码可以控制线程的生命周期。
问题1:既然是后台线程,为什么能看到开始的执行?而不是一开始就什么都看不到
问题2:在通信时用synchrorized和用wait、notify进行控制,是不是会浪费很多资源