并发编程之三种创建线程的方法

jdk一共提供了三种创建线程的方法, 分别是, 继承Thread类, 实现Runnable接口和实现Callable接口;其中Callable可以返回值,下面以购票为例, 对三种方法进行演示

Thread方式:

package ticketwiththread;

public class Ticket extends Thread {

	static int i = 100;
	public Ticket(String name){
		super(name);
	}

	@Override
	public void run() {
		while (true) {

			if (i > 0) {
				try {
					Thread.sleep(10L);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "在售票"
						+ i--);
			}
		}
	}

}
package ticketwiththread;

public class Client {
	public static void main(String[] args) {
		Ticket t1 = new Ticket("窗口1");
		Ticket t2 = new Ticket("窗口2");
		Ticket t3 = new Ticket("窗口3");
		t1.start();
		t2.start();
		t3.start();
	}
}
运行结果(尾部截取)
窗口1在售票7
窗口3在售票6
窗口2在售票5
窗口3在售票4
窗口2在售票3
窗口1在售票2
窗口3在售票1
窗口1在售票0
窗口2在售票-1

出现线程安全问题,一共100张票,而结果出现了-1;    这时候需要加锁, 使用synchronize代码块, 如下例

实现Runnable接口

package ticketwithrunnable;

public class Ticket implements Runnable {

	int i = 100;

	@Override
	public void run() {
		while (true) {
			synchronized (this) {

				if (i > 0) {
					try {
						Thread.sleep(1L);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "在售票"
							+ i--);
				}
			}
		}
	}

}
package ticketwithrunnable;

public class Client {
	public static void main(String[] args) {
		Ticket t = new Ticket();
		Thread t1 = new Thread(t,"窗口1");
		Thread t2 = new Thread(t,"窗口2");
		Thread t3 = new Thread(t,"窗口3");
		t1.start();
		t2.start();
		t3.start();
	}
}

运行的结果:

窗口2在售票8
窗口2在售票7
窗口3在售票6
窗口2在售票5
窗口1在售票4
窗口3在售票3
窗口2在售票2
窗口2在售票1

加上synchronize块后,解决了并发问题, 另外, Thread方法和Runnable方法实现的方式不太一样 ; 注意区别;

在Thread的例子中, 票的数量使用static关键字修饰, 标识各个线程共享此变量, 而Runnable方式中, 只有一个ticket类;

一般情况下, 实现Runnable的方式比较常用, 主要因为java是单继承多实现的机制,实现接口方便一些,


第三种实现Callable接口

package threadcallable;

import java.util.concurrent.FutureTask;

public class Client {
	public static void main(String[] args) {
		Threadtest t = new Threadtest();
		FutureTask<Integer> f = new FutureTask<Integer>(t);
		new Thread(f).start();
		try {
			Integer integer = f.get();
			System.out.println(integer);
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
		}
	}
}	

package threadcallable;

import java.util.concurrent.Callable;

public class Threadtest implements Callable<Integer>{

	@Override
	public Integer call() throws Exception {
		return 100;
	}

}

结果:

100

注意到 , 实现Callable接口实现线程开启需要借助FutureTask类 , 获取方法也需要此类;

这里只演示获取返回值的情况, 卖票的案例与实现Runnable接口的方式相似;

play框架中的job底层使用的就是实现Callable接口的方式开启线程;



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值