用Thread类创建线程
1.要往一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread类的子类。倒过来看,我们要实现多线程,必须编写一个继承了Thread类的子类,子类要覆盖Thread类中的run函数,在子类的run函数中调用想在新的线程上运行的程序代码。
2.启动一个新的线程,我们不是直接调用Thread的子类对象的run方法,二十调用Thread子类对象的start(从Thread类的继承到)方法,Thread类对象的start方法讲产生一个新的线程,并在该线程上运行该Thread类对象中的run方法,根据面向对象的运行的多态性,哎该线程上实际运行的是Thread子类(也就是我们写的那个类)对象中的run方法。
3.由于线程的代码段在run方法中,那么该方法执行完成以后线程也就相应的结束了,因而我们可以通过控制run方法中循环的条件来控制线程的结束。
后台线程与联合线程
1.如果我们对某个线程对象在启动(调用start方法)之前调用了setDaemon(true)方法,这个线程就变成了后台线程。
2.对java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束。
3.pp.join()的作用是吧pp所对应的线程合并倒调用pp.join();语句的线程中。
class TreadDemo1
{
public static void main(String [] args)
//new Thread().start();
Thread tt = new TestThread();
//tt.setDaemon(true);
tt.start();//run();
int index = 0;
while(true)
{
if(index++ == 100)
try(tt.join();)catch(Exception e){}
system.out.println("main(): " + Thread.currentThread().getName());
}
}
class TestThread extends Thread
{
public void run()
{
while(true)
{
System.out.println("run(): "+ Thread.currentThread().getName());
}
}
}
使用runnable接口创建多线程
1.适合多个相同程序的线程去处理同一个资源的情况,把虚拟CPU(线程)同程序的代码、数据有效分离,较好的体现了面向对象的设计思想。
2.可以避免由于JAVA的单继承性带来的局限。我们经常碰到这样的一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同室有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现runnable
3.当线程被构造时,需要的代码和数据通过一个对象座位构造函数实参传递进去,这个对象就是一个实现了runnable接口的类的实例。
4.事实上,几乎所有的多线程都可用runnable接口方式。
class TreadDemo1
{
public static void main(String [] args)
/*new Thread().start();
Thread tt = new TestThread();
//tt.setDaemon(true);
tt.start();//run();
int index = 0;
while(true)
{
if(index++ == 100)
try(tt.join();)catch(Exception e){}
system.out.println("main(): " + Thread.currentThread().getName());
}*/
TestThread tt = new TestThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}
class TestThread extends Thread
{
int ticket = 100;
public void run()
{
while(true)
{
System.out.println("run(): "+ Thread.currentThread().getName() +" is saling ticket " + ticket--);
}
}
}
多线程在实际中的应用
1.网络聊天程序的收发
-1)如果一方从键盘上读取了数据病发送给对方,程序运行倒读取对方回送的数据并一直等待对方回送数据,如果对方没有回应,程序不能再做任何其他事情,这事程序处于阻塞状态,即使用户想正常准终止程序都不可能,更不能实现再给对方发送一条信息,催促对方赶快应答这样的事情了。
-2)如果程序没有事先从键盘上读取数据并向外发送,程序将一直在从键盘上读取数据出阻塞,即使有数据从网撒谎那个发送过来,程序无法到达读取对方回送的数据出,程序将不能收到别处先主动发送过来的数据。
2.表记录的复制的中途取消
3.www服务器为每一个来访者都敬爱那里专线服务。
线程间的通信
生产者、消费者和缓冲区
1.wait:告诉当前的线程放弃监视器并进入睡眠状态直到其他线程进入同一监视器病调用notify为止。
2.notify:唤醒同一对象监视器中调用wait的第一个线程。用于类似饭馆有一个空位后通知所有等候就餐的顾客中的第一位可以入桌的情况。
3.notify All:唤醒
相关代码;
class Producer implement Runnable
{
Q q;
public Producer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
synchronized(q)
{
if(i == 0)
{
q.name="zhangsan";
try{Thread.sleep(1);}catch(Exception e){}
q.sex="male";
}
else
{
q.name="lisi";
q.sex="female";
}
}
i = (i+1)%2;
}
}
}
class customer implement Runnable
{
Q q;
public Customer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
synchornized()
{
System.out.println(q.name);
System.out.println(":" + q.sex);
}
}
}
}
class Q
{
String name="unknow";
String sex="unknow";
}
public ThreadCommunation
{
public static void main(String []args)
{
Q q= new Q();
new Thread(new Producer(q)).start();
new Thread(new Customer(q)).start();
}
}
该代码只能实现线程之间的同步,但是没有执行线程之间的通行。例如,在消费者成功取出数据前,生产者又再一次更新了数据,
修改的代码:
class Producer implement Runnable
{
Q q;
public Producer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
synchronized(q)
{
wait(bFull)
wait();
if(i == 0)
{
q.name="zhangsan";
try{Thread.sleep(1);}catch(Exception e){}
q.sex="male";
}
else
{
q.name="lisi";
q.sex="female";
}
bFull= true;
notify();
}
i = (i+1)%2;
}
}
}
class customer implement Runnable
{
Q q;
public Customer(Q q)
{
this.q = q;
}
public void run()
{
while(true)
{
synchornized()
{
if(!q.bFull)
wait();
System.out.println(q.name);
System.out.println(":" + q.sex);
bFull=false;
notify();
}
}
}
}
class Q
{
String name="unknow";
String sex="unknow";
boolean bFull= false;
}
public ThreadCommunation
{
public static void main(String []args)
{
Q q= new Q();
new Thread(new Producer(q)).start();
new Thread(new Customer(q)).start();
}
}
public synchronized void sale()
{
if (tickets > 0)
}
张孝祥 java 基础教程笔记 第五讲
最新推荐文章于 2021-11-28 15:16:07 发布