Java多线程
Java实现多线程有四种方式:
1.继承Thread类;
2.实现Runable接口;
3.实现Callable接口,通过FutureTask包装器来创建Thread线程;
4.使用ExecutorService、Callable、Future实现有返回结果的多线程;
其中前两种线程执行完是没有返回结果的,后两种是有返回值的。
先贴出一个多线程售票的简单示例,根据代码去理解多线程:
/*** 一个售票类,实现Runnable接口重写run()方法来实现线程*/@Datapublic class SellTicket implementsRunnable{//票总数
private inttickets;
SellTicket(inttickets){this.tickets =tickets;
}
@Overridepublic voidrun() {while(true) {//锁,如果这里不加锁的话,当多个线程同时进入tickets > 0时,可能会出现最后余票为-1,-2的情况
synchronized (this){if(tickets > 0) {try{
Thread.sleep(100);
}catch(Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "卖掉一张票,剩下: " + --tickets +"张");
}else{break;
}
}
}
}
}
/*** 测试类*/
public classTest {public static voidmain(String[] args) {
SellTicket p1= new SellTicket(20);
Thread t1= new Thread(p1,"线程1");
Thread t2= new Thread(p1,"线程2");
Thread t3= new Thread(p1,"线程3");//setPriority(),参数为1-10,参数越大,优先级越高,参数超过10会报错//t1.setPriority(1);//t2.setPriority(2);//t3.setPriority(10);
t1.start();
t2.start();
t3.start();
}
}
运行结果:
在测试类中,如果将注释的优先级放开,那执行结果都会是线程3在售票,当票数更多时,线程1和线程2也会开始售票。当有优先调度需求时,setPriority()就能派上用场。
总结:
1. 前两种创建多线程的方式差不多,只是因为Java只支持单继承但可以实现多个接口,所以继承Thread类来实现接口会有一定的局限性。
2.Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
修改售票示例,通过实现Callable接口实现多线程,并知道线程2卖了多少张票:
/*** 一个售票类,实现Callable接口重写call()方法来实现线程*/@Datapublic class SellTickets implements Callable{//票总数
private inttickets;
SellTickets(inttickets){this.tickets =tickets;
}
@OverridepublicInteger call() {int thread2 = 0;while(true) {//锁,如果这里不加锁的话,当多个线程同时进入tickets > 0时,可能会出现最后余票为-1,-2的情况
synchronized (this){if(tickets > 0) {try{
Thread.sleep(100);
}catch(Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+ "卖掉一张票,剩下: " + --tickets +"张");if("Thread-1".equals(Thread.currentThread().getName())){
thread2++;
}
}else{break;
}
}
}returnthread2;
}
}
/*** 测试类*/
public classTest {public static voidmain(String[] args) {
Callable callable = new SellTickets(100);
FutureTask futureTask = new FutureTask<>(callable);
Thread thread= newThread(futureTask);
thread.start();
FutureTask futureTask2 = new FutureTask<>(callable);
Thread thread2= newThread(futureTask2);
thread2.start();//获取线程2的返回值
Integer sum = 0;try{
sum=futureTask2.get();
}catch(Exception e){
e.printStackTrace();
}
System.out.println("线程2售票:"+sum+"张");
}
}
具体是创建Callable接口的实现类,并实现call()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。首先,我们发现,在实现Callable接口中,此时不再是run()方法了,而是call()方法,此call()方法作为线程执行体,同时还具有返回值!