一.线程创建的两种方式
1.第一种方式:继承Thread类
//定义一个子线程的类,继承Thread类
public class SubThread extends Thread {
/*在子线程类中重写run方法,在run方法中打印子线程的名称;*/
public void run() {
// 打印子线程的名称
System.out.println("subThread:" + Thread.currentThread().getName());
}
}
//定义一个测试类
public class ThreadDemo {
public static void main(String[] args) {
// 在main方法中打印主线程的名称;
System.out.println("main:" + Thread.currentThread().getName());
// 在main方法中创建子线程对象;
SubThread st = new SubThread();
// 调用子线程对象的start方法,开启子线程。
st.start();
}
}
2.实现Runnable接口(更重要)
public class SubRunnable implements Runnable {
@Override
public void run() {
// 2.在子任务类中重写run方法,在run方法中打印子线程的名称。
System.out.println("SubRunnable:"+ Thread.currentThread().getName());
}
}
public class RunnableDemo {
public static void main(String[] args) {
// 4.在main方法中打印主线程的名称。
System.out.println("RunnableDemo:"+ Thread.currentThread().getName());
// 5.在main方法中创建一个子任务对象。
SubRunnable r = new SubRunnable();
// 6.在main方法中创建一个Thread类的对象,并把子任务对象传递给Thread类的构造方法。
Thread t = new Thread(r);
// 7.调用Thread类对象的start方法开启子线程。
t.start();
}
}
问题:第二种实现Runnable接口的优势
- 适合多个相同的程序代码的线程去共享同一个资源。
- 可以避免java中的单继承的局限性。
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和数据独立。
- 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类。
3.第二种方式的改进:使用匿名内部类方式实现线程的创建
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
},"t1").start();
线程安全
public class SellTicketTask implements Runnable {
private int tickets = 100;
Lock l = new ReentrantLock();
@Override
public void run() {
while (true) {
l.lock();
if (tickets > 0) {
try {
Thread.sleep(10);//线程休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "还有" + tickets + "张票");
tickets--;
}
l.unlock();
}
}
}
线程状态
线程的六种状态:
1.new(新建)
2.Runnable(可运行)
3.Blocked(锁阻塞)
4.Waiting(无限等待)
5.Timed Waiting(计时等待)
6.Teminated(被终止)
a)任务结束
b)遇到异常