练习题1.0版本
首先结合第一种方式举个例子,然后由例子引入第二种方式
例子:创建三个窗口卖票,总票数是100张
package com.jsm.Java2;
/*
例子:创建三个窗口卖票,总票数是100张
*/
public class ThreadTest {
public static void main(String[] args) {
Window3 w1 = new Window3();
Window3 w2 = new Window3();
Window3 w3 = new Window3();
w1.start();
w2.start();
w3.start();
}
}
class Window3 extends Thread{
private static int num =100;//车票为100张(关键,这个num变量必须设置为100,不然每一个对象都能调用,应该是一个共用性质的数据)
@Override
public void run() {
while (true){
if (num>0){
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+num);
num--;
}else {
break;
}
}
}
}
运行结果(这里过于冗杂就不粘贴结果,但是对结果出现的问题和注意点进行解释):
- 出现了每个线程都卖100张,一共卖了300张票的情况?
答:总票数未设置为static,因为票是大家共用的,所以要设置为静态属性
- 设置为static之后出现少量重复票号的情况
答:涉及到线程的安全问题,这个在后面的文章中详细讲解
- 运行结果存在号码高的在后面,而号码低的在前面是为什么?
答:实际结果是依次递减的,只是没有及时的显式出来而已
正文
例子中总票数用关键字static设置为静态属性,那么假如不想设置为静态属性,还有没有其他办法呢?
创建方式二:实现Runnable接口
- 创建一个实现Runnable接口的类
- 实现类去实现Runnable中的抽象方法:run()
- 创建实现类的对象
- 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
- 通过Thread类的对象调用start()方法
package com.jsm.Java2;
public class ThreadTest {
public static void main(String[] args) {
//3. 创建实现类的对象
MyThreadRunnable m1 = new MyThreadRunnable();
//4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
Thread t1 = new Thread(m1);
t1.start();
//再启动一个线程,遍历100以内的偶数
Thread t2 = new Thread(m1);
t2.start();
}
}
//1. 创建一个实现Runnable接口的类
class MyThreadRunnable implements Runnable{
//2. 实现类去实现Runnable中的抽象方法:run()
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
//这里不能直接写getName方法,因为这里没有继承于Thread,和第一种方法略有区别
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
}
练习题2.0版本
ps:这里用实现Runnable接口的方式做篇首的例题
package com.jsm.Java2;
//这里用实现Runnable接口的方式做之前抢票的例题
public class LXT {
public static void main(String[] args) {
Window2 w1 = new Window2();
Thread t1 = new Thread(w1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(w1);
t1.start();
t2.start();
t3.start();
}
}
class Window2 implements Runnable{
private int num =100;//未加static,因为此时三个线程共用同一个num,此时只造了一个对象
@Override
public void run() {
while (true){
if (num>0){
System.out.println(Thread.currentThread().getName()+"卖出的票号为:"+num);
num--;
}else{
break;
}
}
}
}
比较创建线程的两种方式
开发中:优先选择实现Runnable接口的方式
原因:
- 实现的方式没有类的单继承性的局限性
- 实现的方式更适合来处理多个线程有共享数据的情况
联系:Thread本身也实现了Runnable接口
相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run方法中
区别:
继承Thread:线程代码存放Thread子类run方法中。
实现Runnable接口:线程代码存在接口的子类的run方法
实现方式的好处:
- 避免了单继承的局限性
- 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线 程来处理同一份资源。