多线程处理相关

来源:互联网 发布:销售数据分析报告ppt 编辑:程序博客网 时间:2024/06/05 15:45

程序:计算机指令的集合;

进程:一个程序在其自身地址空间中的一次执行活动,是资源申请调度的单位;

线程:进程中一个单一的连续控制流程。一个进程可以拥有多个线程。但线程没有独立的存储空间,而是和该进程中的其他线程共享一个存储空间。

注:(1)单CPU的情况下,某个时刻只能出现一个线程。

        之所以出现一个时刻可以看到很多线程,是因为由操作系统给所有线程划分时

间片,不断在之间切换。这个时间片很短,所以好像同一时间出现多个线程;

         (2)多CPU的平台下,可以实现多线程的并发运行;

     (3)多线程之间切换时,只需改变执行路线和局部变量即可。切换效率高。无需像

进程一样交换地址;

  

Java对多线程的支持

线程是在系统层实现,但Java在语言级就实现了。需要使用提供的特定接口。

 

两种方式:(1)从Thread类继承  (2)实现Runnable接口

 

第一种方式的代码:

Class MultiThread

{

        publicstatic void main(String[] args)

        {

               MyThreadmythread = new MyThread();

               mythread.start();//新线程启用

               system.out.println("Current name is"+Thread.currentThread.getName());

        }

}

 

Class MyThread extends Thread

{

        publicvoid run()//线程的入口,必须有。里面放置需要实现的代码

        {

                      system.out.println("Thisis thread is "+currentThread.getName());

        }

}

 

运行结果:先打印main,后打印mythread。

 

分析:虽然启用了新线程,但主线程的时间片仍未到期。所以主线程继续向下运行,打印,待到线程结束后运行新线程中的内容。

1、  设置后台线程

myThread.setDaemon(true);

注:当系统中只剩后台线程时,自动退出。

 

2、暂停当前线程,调用其他线程

yield();

 

3、线程的优先级

设置优先级:setPriority(MAX/MIN/NORM_PRIORITY);

(Thread类里的最大/最小/缺省)

事实上,这三个参数分别代表着整数10、1、5,也就是说1-5的整数值都可以作为参数使用;

获得优先级:getPriority()

注意:java支持的是抢占性调度模型,同一时间点有多个线程处于可运行但未运行状态,即等待状态。只有一个线程处于运行状态。此线程终止运行有两种情况:1、自然终止,运行完毕

          2、有比起优先级高的线程处于等待状态,此时会被抢占

 

4、第二种方式:实现Runnable接口

一个类,如果想要它的实例被一个线程运行,就必须在这个类中实现Runnable

接口,在其中定义一个不带参数的run()方法【这个接口只有这一个方法】事实上,之所以可以用继承Thread的方式来创建实现某功能的线程,也是因为Thread实现了Runnable接口。

第二种方式的代码:

Class MultiThread

{

                     publicstatic void main(String[] args)

                     {

                            MyThread mythread = new MyThread();

                            //以实现了接口的实例做参数,建立一个新线程,并start();

                      newThread(mythread).start();

                            system.out.println(Thread.currentThread.getName());

                     }

}

 

Class MyThread implements Runnable

{

                     publicvoid run()//线程的入口,必须有。里面放置需要实现的代码

                     {

                            system.out.println(Thread.currentThread.getName());

                     }

}

 

 

这两种方式有什么不一样

一般情况下推荐使用Runnable接口实现的方式建立新线程。

多个线程访问同一种资源的时候比较方便。

如以下代码:

代码:

Class MultiThread

{

                     publicstatic void main(String[] args)

                     {

                            MyThread mythread = new MyThread();

                            //以实现了接口的实例做参数,建立一个新线程,并start();

                      newThread(mythread).start();

new Thread(mythread).start();

new Thread(mythread).start();

                            system.out.println(Thread.currentThread.getName());

                     }

}

 

Class MyThread implements Runnable

{

              intindex=0;

                     publicvoid run()//线程的入口,必须有。里面放置需要实现的代码

                     {

                            system.println(Thread.currentThread.getName()+index++);

                     }

}

 

说明:虽然建立了3个新的线程,但由于传进去的都是mythread实例,其访问的是同一个index,故打印出来的index的数字是递增的。这样可以保证某些参数被多个线程共享,从而达到变化的连续性。

补充:这个优点是可以通过匿名内部类实现的。以后要特别注意运用来实现需要的功能。

     代码:

         Class MultiThread

{

                     publicstatic void main(String[] args)

                     {

                            MyThreadmythread = new MyThread();

                            //下面开三个线程依旧共用一个实例

                            mythread.getThread().start();

                            mythread.getThread().start();

mythread.getThread().start();

                            system.out.println("Currentthread's name is "+Thread.currentThread.getName());

                     }

}

 

Class MyThread

{

                    intindex=0;

                     private Class innerThread extends Thread

                     {

                            publicvoid run()

                            {

                     system.out.println("Thisis thread is "+Thread.currentThread.getName()+index++);

                            }

                     }

           //把上面的内部类定义为私有了,通过一个get方法返回需要的线程类

                     Thread getThread()

{

return innerThread;

}

}

 

利用多线程简单搭建火车票售票系统

代码

Class MultiThread

{

              public static void main(String[]args)

              {

                     MyThread mythread = newMyThread();

                     //新建4个线程

                     for(i=0;i<=3;i++)

                     {

                            newThread(mythread).start();

                     }

              }

}

 

Class MyThreadimplements Runnable

{

            int ticketNum=100;

              public void run()

              {

                     while(true)

                     {

                            if(ticketNum>0)

                            {

                                   system.out.println("thread"+Thread.currentThread().getName()+"selltickes"+ticketNum);\

                                   ticketNum--;

                            }

                     }

              }

}

 

存在潜在的问题:时间片的结束、交替跳过了判断语句,导致余票为负,且一直往下错误的运行。这种情况在系统长时间运行过程中是有可能出现的,但短时间出现概率低。若需要观察,可以使用Thread.sleep(1000)来使得一个线程休眠,从而让错误出现。

       由此引入下面的解决方案。

 

线程的同步

1、可能出现线程交替而发生异常的区域成为临界区

2、同步的两种方式:同步块,同步方法

3、同步块

原理:放置一个监听器(object),并给该监听器加锁。如果有线程已经在运行锁里面的代码,其他线程只能等待。待运行完,才能进入第二个线程,并重新加锁。

代码:


Class MyThread implements Runnable

{

  int ticketNum=100;

         Object object = new Object()

        publicvoid run()

        {

                             while(true)

                             {

                                          synchronized(object)

                                    {

                                                  if(ticketNum>0)

                                                  {

                                                         try

                                                         {

                                                                Thread.sleep(1000);

                                                         }

                                                         catch(Exceptione)

                                                         {

                                                                e.printStackTrace();

                                                         }

                                                         system.out.println("thread"+Thread.currentThread().getName()+"selltickes"+ticketNum);\

                                                         ticketNum--;

                                                  }

                                    }    

                             }

        }

}

 

4、同步方法:

原理:在方法前面加关键字,调用时候即是同步的。实质是给该类的this加锁。

代码:public syncronized void sell()。

 

5、另:main也是一个线程,当这个线程的时间片没有结束时,在main里面所建立的线程建立了,但实际上是没有被运行的。待到main结束后,才能运行。


6、静态方法只属于类本身,不属于某个对象。对其调用也是直接从类中调用。

每个类也有一个锁,是对应的Class对象的锁。

 

7、线程的死锁

1、线程1进入并锁住了对象A的监视器;

2、线程2进入并锁住了对象B的监视器;

3、对象B在对象A中,线程1进不去对象B,等待;

4、对象A也在对象B中,线程2进不去对象A,等待。

造成死锁。

 

8、wait, notify, notifyAll

每个对象除了有一个锁外,还有一个等待队列(wait set)。应当在当前线程锁住对象时,去调用该对象的wait方法。当调用其notify方法时,会从其等待队列中任意删除一个线程,使其成为可运行的;当调用其notifyAll方法时,会清空其等待队列,使其均可以运行。

 

0 0
原创粉丝点击