在java中要想实现多线程,有两种手段,一种是继承Thread类,另外一种是实现Runable接口。
1、继承Thread:
类名 extend Thread{
public void run(){
// other code…
}
public static void main(String[] args) {
类名 t = new 类名();
t.start();
}
}
2、通过实现Runnable接口:
类名 implements Runnable{
public void run(){
// other code…
}
public static void main(String[] args) {
类名 t = new 类名();
new Thread(t,"线程名").start();
}
}
线程
其实Thread中的run方法调用的是Runnable接口的run方法。
Thread和Runnable的区别:
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
/**
*
* @author ZYL
*
*/
public class ThreadShare extends Thread{
private String name;
private int ticket = 5;
public ThreadShare(String name){
this.name = name;
}
public void run() {
for (int i = 0; i < 20; i++) {
if (ticket > 0) {
System.out.println(name+ "正在卖票"+this.ticket--);
}
}
}
public static void main(String[] args) {
ThreadShare h1 = new ThreadShare("1号窗口:");
ThreadShare h2 = new ThreadShare("2号窗口: ");
ThreadShare h3 = new ThreadShare("3号窗口: ");
h1.start();
h2.start();
h3.start();
}
}
【运行结果】:
1号窗口:正在卖票5
3号窗口: 正在卖票5
2号窗口: 正在卖票5
2号窗口: 正在卖票4
2号窗口: 正在卖票3
2号窗口: 正在卖票2
2号窗口: 正在卖票1
3号窗口: 正在卖票4
1号窗口:正在卖票4
1号窗口:正在卖票3
3号窗口: 正在卖票3
1号窗口:正在卖票2
3号窗口: 正在卖票2
1号窗口:正在卖票1
3号窗口: 正在卖票1
假设这是一个买票程序,显然这是不对的。五张票卖了15次。
Runnable接口
class MyThread implements Runnable{
private int ticket = 5; //5张票
public void run() {
for (int i=0; i<=20; i++) {
if (this.ticket > 0) {
System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--);
}
}
}
}
public class lzwCode {
public static void main(String [] args) {
MyThread my = new MyThread();
new Thread(my, "1号窗口").start();
new Thread(my, "2号窗口").start();
new Thread(my, "3号窗口").start();
}
}
【运行结果】:
1号窗口正在卖票5
2号窗口正在卖票4
3号窗口正在卖票2
1号窗口正在卖票3
2号窗口正在卖票1
这种结果才是我们期望的样子
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
线程的控制
1、线程睡眠 sleep
让正在执行的线程暂停,进入阻塞状态:Thread.sleep(时间(毫秒));
注意问题:sleep是静态方法,不能使用线程实例去调用。
2、线程让步 yield
让正在执行的线程暂停,不会进入阻塞状态,直接进入就绪状态。Thread.yield();
关于sleep()方法和yield()方的区别如下:
①、sleep方法暂停当前线程后,会进入阻塞状态,只有当睡眠时间到了,才会转入就绪状态。而yield方法调用后 ,是直接进入就绪状态,所以有可能刚进入就绪状态,又被调度到运行状态。
②、sleep方法声明抛出了InterruptedException,所以调用sleep方法的时候要捕获该异常,或者显示声明抛出该异常。而yield方法则没有声明抛出任务异常。
③、sleep方法比yield方法有更好的可移植性,通常不要依靠yield方法来控制并发线程的执行。