Java中的多线程实现方式

2017-03-03  本文已影响0人  Promisesaybye

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实现多线程。
上一篇下一篇

猜你喜欢

热点阅读