您的位置:首页 > 编程语言

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

2018-03-13 20:42 225 查看
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接口的方式开启线程;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: