java多线程(内附实例:窗口售票问题、人和叉子的问题)

时间:2022-04-26
本文章向大家介绍java多线程(内附实例:窗口售票问题、人和叉子的问题),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

java多线程的开发有两种方法:

(1)实现Runnable接口;

(2)继承Thread类;

区别:

(1)由于java中一个类只能继承一个父类,但是可以实现多个接口,所以实现Runnable接口比继承Thread更灵活。

(2)实现Runnable接口,最终还是要用Thread(Runnable)、Thread(Runnable,String)等构造函数调用,但是此时可以多个Thread共用一个Runnable,实现资源共享(详见后面售票的实例),当然也可以使用不同的Runnable(详见后面人与叉子的实例),从这点看实现Runnable接口也比继承Thread类更灵活。

联系:

Thread类其内部实现如下:

public class Thread extends Object implements Runnable,可以看出Thread类也是Runnable接口的子类;

实例1:售票问题,假设现在有三个窗口进行售票(并发执行)。

用实现Runnable接口的方法实现代码如下:

package ticket2;

public class ticket2 
{
    public static void main(String []args)
    {
        Show_tickets show_ticket=new Show_tickets();
        new Thread(show_ticket,"windows1").start();
        new Thread(show_ticket,"windows2").start();
        new Thread(show_ticket,"windows3").start();
    }
}
class Show_tickets implements Runnable
{
    private int tickets=10;
    public void run()
    {
        while(true)
        {
            if(tickets>0)
            {
                System.out.println(Thread.currentThread().getName()+" showed the ticket"+tickets--);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            else
            {
                break;
            }
        }
    }
}

执行结果:

windows1 showed the ticket10 windows2 showed the ticket9 windows3 showed the ticket8 windows2 showed the ticket7 windows1 showed the ticket6 windows3 showed the ticket5 windows1 showed the ticket4 windows2 showed the ticket3 windows3 showed the ticket2 windows2 showed the ticket1

用继承Thread实现如下:

package ticket1;

public class ticket1 
{
    public static void main(String []args)
    {
        new Show_tickets("window1").start();
        new Show_tickets("window2").start();
        new Show_tickets("window3").start();
    }
}

class Show_tickets extends Thread
{
    private int tickets=10;
    private String name;
    Show_tickets(String sname)
    {
        this.name=sname;
    }
    public void run()
    {
        while(true)
        {
            if(tickets>0)
            {
                System.out.println(name+" showed the ticket"+tickets-- );
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            else
            {
                break;
            }
        }
    }
}

执行结果如下:

window1 showed the ticket10 window2 showed the ticket10 window3 showed the ticket10 window3 showed the ticket9 window2 showed the ticket9 window1 showed the ticket9 window1 showed the ticket8 window2 showed the ticket8 window3 showed the ticket8 window3 showed the ticket7 window2 showed the ticket7 window1 showed the ticket7 window1 showed the ticket6 window2 showed the ticket6 window3 showed the ticket6 window3 showed the ticket5 window2 showed the ticket5 window1 showed the ticket5 window1 showed the ticket4 window2 showed the ticket4 window3 showed the ticket4 window3 showed the ticket3 window2 showed the ticket3 window1 showed the ticket3 window1 showed the ticket2 window2 showed the ticket2 window3 showed the ticket2 window3 showed the ticket1 window2 showed the ticket1 window1 showed the ticket1

可见由于方法1中Show_tickets类是被实例化之后,给三个进程共用的,所以相当于3个窗口一共有10张票大家来卖,而方法2中由于每一个Show_tickets都被实例化为一个对象,所以其中的变量tickets也就是独立的,相当于每一个窗口都有10张票。(当然方法2中也可以用static实现共享)

实例2 人和叉子的问题,有5个人,5个叉,他们围城一圈,叉子依次摆在他们相邻的地方,只有一个人的左右手边叉子都没被用的时候,这个人才拿起叉子(左右2个都被拿起)吃饭,吃完后1秒,将叉子放下,若每个人吃一次之后就不再吃了,模仿他们吃饭的顺序。

用实现Runnable接口的方法实现代码如下:

package person1;

public class personfork 
{
    public static void main(String []args)
    {
        Forks fork=new Forks();
        Person person1=new Person("person1",fork);
        new Thread(person1,"0").start();;
        Person person2=new Person("person2",fork);
        new Thread(person2,"1").start();
        Person person3=new Person("person3",fork);
        new Thread(person3,"2").start();
        Person person4=new Person("person4",fork);
        new Thread(person4,"3").start();
        Person person5=new Person("person5",fork);
        new Thread(person5,"4").start();
    }
}

class Person implements Runnable
{
    private String person_name;
    private Forks fork;
    Person(String name,Forks fork_input)
    {
        this.person_name=name;
        this.fork=fork_input;
    }
    public void run()
    {
        fork.get_fork();
        System.out.println("i am eating " + person_name);
        try 
        {
            Thread.sleep(1000);
        } catch (InterruptedException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        fork.put_fork();
    }
}
class Forks
{
    private int forks[]={0,0,0,0,0};
    public synchronized void get_fork()
    {
        String thread_name=Thread.currentThread().getName();
        int num=Integer.parseInt(thread_name);
        while(1 == forks[num] || 1 == forks[(num+1)%5])
        {
            try 
            {
                wait();
            } catch (InterruptedException e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        forks[num]=1;
        forks[(num+1)%5]=1;
    }
    public synchronized void put_fork()
    {
        String thread_name=Thread.currentThread().getName();
        int num=Integer.parseInt(thread_name);
        forks[num]=0;
        forks[(num+1)%5]=0;
        notifyAll();
    }
}

用继承Thread实现如下:

package personfork;


public class personfork
{
    public static void main(String []args)
    {
        Fork fork=new Fork();
        new Person("person1","0",fork).start(); 
        new Person("person2","1",fork).start(); 
        new Person("person3","2",fork).start(); 
        new Person("person4","3",fork).start(); 
        new Person("person5","4",fork).start(); 
    }
}

class Person extends Thread
{
    private String person_name;
    //private String thread_name;
    private Fork fork;
    Person(String person_name1,String thread_name1,Fork fork1)
    {
        super(thread_name1);
        //person_name=person_name1;
        //fork=fork1;
        this.person_name=person_name1;
        this.fork=fork1;
    }
    public void run()
    {
        //System.out.println("I am Eating:"+person_name);
        fork.get_fork();
        System.out.println("I am Eating:"+person_name);
        try {
            sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        fork.put_fork();
    }
}
class Fork
{
    private int forks []={0,0,0,0,0};
    public synchronized void get_fork()
    {
        int num=Integer.parseInt(Thread.currentThread().getName());
        while(1==forks[num] || 1==forks[(num+1)%5])
        {
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        forks[num]=1;
        forks[(num+1)%5]=1;
    }
    public synchronized void put_fork()
    {
        int num=Integer.parseInt(Thread.currentThread().getName());
        forks[num]=0;
        forks[(num+1)%5]=0;
        notifyAll();//唤醒其他线程
    }
}

两种方法的结果一样基本都是5个人随机吃一遍,这里的Person是不同的5个人,所以在实现Runnable接口的方法中也并没有将其共享资源,而是放到5个不同的线程中。