美文网首页
Java中的多线程实现方式

Java中的多线程实现方式

作者: Promisesaybye | 来源:发表于2017-03-03 18:03 被阅读0次

    Java中的多线程实现方式

    在我们的开发的过程中,常常会碰到多线程的问题,对于多线程的实现方式主要有两种:实现Runnable接口集成Thread类。对于这两种多线程实现的方式也是有一些差异的。网上针对此问题基本都是使用买票系统的例子,接下来我们就用代码来模拟下售票系统,实现2个售票点发售10张车票,一个售票点表示一个线程。

    方案一

    首先从最简单的做法开始,开两个Thread类进行售票。
    测试代码如下

    public class ticketThread extends Thread {
    
        private int ticket = 10;
        
        public void run() {
            for(int i = 0; i < 10; i++){
                if(ticket > 0){
                    try {
                        sleep(1000);
                        System.out.println(Thread.currentThread().getName() 
                                + "卖票 ——>" + (ticket--) );                  
                    } catch (Exception e) {
                        // TODO: handle exception
                        e.printStackTrace();
                    }
                }
            }
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            new ticketThread().start();
            new ticketThread().start();
        }
    
    }
    

    测试结果:
    Thread-0卖票 ——>10
    Thread-1卖票 ——>10
    Thread-1卖票 ——>9
    Thread-0卖票 ——>9
    Thread-1卖票 ——>8
    Thread-0卖票 ——>8
    Thread-1卖票 ——>7
    Thread-0卖票 ——>7
    Thread-0卖票 ——>6
    Thread-1卖票 ——>6
    Thread-0卖票 ——>5
    Thread-1卖票 ——>5
    Thread-1卖票 ——>4
    Thread-0卖票 ——>4
    Thread-1卖票 ——>3
    Thread-0卖票 ——>3
    Thread-1卖票 ——>2
    Thread-0卖票 ——>2
    Thread-0卖票 ——>1
    Thread-1卖票 ——>1
    结论:
    从上面的测试结果可以看出,两个线程各自卖了各自的10张票而不是去卖共同的10张票,这和我们的目标多个线程去处理同一个资源相差很多。我们创建了2个ticketThread对象就等于创建了2个资源,每个资源有10张票,每个资源都在独自处理各自的资源。所以通过这个例子我们知道,在这个售票系统中,我们只能创建一个资源对象,但需要创建多个线程去处理同一个资源对象,并且每个线程上所运行的是相同的程序代码。

    方案二

    既然只能创建一个资源对象,那么我就只创建一个ticketThread,在额外创建两个新的线程去实现售票。

    测试代码:

    public class ticketThread extends Thread {
    
        private int ticket = 10;
        
        public void run() {
            for(int i = 0; i < 10; i++){
                synchronized(this){
                    if(ticket > 0){
                        try {
                            sleep(1000);
                            System.out.println(Thread.currentThread().getName() 
                                    + "卖票 ——>" + (this.ticket--) );                 
                        } catch (Exception e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            ticketThread t1 = new ticketThread();
            new Thread(t1, "线程1").start();
            new Thread(t1, "线程2").start();
        }
    
    }
    

    测试结果:
    线程1卖票 ——>10
    线程1卖票 ——>9
    线程2卖票 ——>8
    线程2卖票 ——>7
    线程2卖票 ——>6
    线程1卖票 ——>5
    线程1卖票 ——>4
    线程2卖票 ——>3
    线程2卖票 ——>2
    线程2卖票 ——>1

    结论:
    这种情况下,我们实现了多个线程对同一个资源进行处理。这里我们创建新线程使用了
    Thread(ThreadGroup groupOb, String threadName)
    ticketThread作为参数传入新创建的线程。在这种情况下新创建的两个线程就去执行了ticketThread中的run()方法,这样一来就实现了两个线程对同一个资源进行处理。但就原理上来说,此方案与方案三是一样的。

    方案三

    使用Runnable来实现多线程。
    测试代码:

    public class ticketThread implements Runnable {
    
        private int ticket = 10;
        
        public void run() {
            for(int i = 0; i < 10; i++){
    //          synchronized(this){
                    if(ticket > 0){
                        try {
                            Thread.sleep(1000);
                            System.out.println(Thread.currentThread().getName() 
                                    + "卖票 ——>" + (ticket--) );   
                        } catch (Exception e) {
                            // TODO: handle exception
                            e.printStackTrace();
                        }
                    }
                }
    //      }
        }
        
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            ticketThread t1 = new ticketThread();
            new Thread(t1, "线程1").start();
            new Thread(t1, "线程2").start();
        }
    
    }
    
    
    

    测试结果:
    线程1卖票 ——>10
    线程2卖票 ——>9
    线程2卖票 ——>7
    线程1卖票 ——>8
    线程1卖票 ——>6
    线程2卖票 ——>5
    线程1卖票 ——>4
    线程2卖票 ——>3
    线程2卖票 ——>2
    线程1卖票 ——>1

    结论
    在上面的测试代码中,我们创建了2个线程,每个县城调用的是同一个ticketThread对象中的run()方法,访问的是同一个对象的变量(ticket)的实例,这个程序就完美的满足了我们的需求。

    Runnable与Thread的区别与联系

    1. 一个类只能继承一个父类,这是使用Thread的局限性,而Runnable是一个接口,只要实现这个接口就行了。所以在实际的开发过程中,是通过Runnable接口来实现的,并且Runnable更适合资源共享的实现。
    2. 使用Runnable可以比喵由于Java的单继承特性带来的局限性,我们经常碰到这样一种情况,即当我们要已经继承了某一个累的子类放入多线程中,由于一个类不能同时偶两个父类,所以不能用继承Thread类的方式,那么这个类就是只能采用Runnable接口的方式了。
    3. 实际上Thread类也是Runnbale接口的子类。
      public class Thread extends Object implements Runnable
    4. 使用Runnable对象时,Runnable定义的子类没有start()方法,只有Thread类中才有,观察Thread类,有一个构造方法public Thread(Runnable target),此构造方法接受Runanble的子类实例,也就是说可以通过Thread类来启动Runnable实现多线程。

    相关文章

      网友评论

          本文标题:Java中的多线程实现方式

          本文链接:https://www.haomeiwen.com/subject/bfprgttx.html