按照万物皆对象的思想,Java实现创建线程肯定是通过某个类或者某个借口来实现的,也就是说某个类或接口的一个实例就是一个线程。Java中便提供了Runable类和Thread类来帮我们创建线程。
继承Thread类创建线程
若某个类想让它的实例称为一个线程,继承Thread类,再覆盖run()方法即可。
- 创建类
public class ExtThread extends Thread{
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(this.getName() +" " + i);
}
}
}
- 创建线程
public static void main(String[] args) {
Thread et1 = new ExtThread();
Thread et2 = new ExtThread();
et1.start();
et2.start();
}
实现Runnable接口创建线程
创建一个类实现Runnable接口,实现的run()方法就是线程中真正执行的方法。
- 创建类
public class ImpRunnable implements Runnable {
public void run() {
for(int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " "+i);
}
}
}
- 创建线程
public static void main(String[] args) {
ImpRunnable ir = new ImpRunnable();
Thread t1 = new Thread(ir);
Thread t2 = new Thread(ir);
t1.start();
t2.start();
}
Thread&Runnable
JDK第一句对Runnable的解释是:The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. 所以任何可以创建线程的类都实现了Runnable 接口,Thread也不例外:JDK中:public class Thread implements Runnable { ... }。所以对线程进行操纵的类是Thread类,起核心功能的是Runnable中的run()方法。
在实际使用时多使用实现Runnable接口创建线程这种方式。因为Java只支持单一继承,继承Thread类之后不方便拓展其他功能。
synchronized
经典案例,买票问题。
- 卖票类
public class Ticket implements Runnable{
private int tickets = 100;
public void run() {
while(true) {
if(tickets > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("正在卖第" + tickets-- + "张票");
}else
System.exit(0);
}
}
}
- 三个卖票窗口卖票
public static void main(String[] args) {
Ticket ticket = new Ticket();
//三个买票窗口
Thread t1 = new Thread(ticket);
Thread t2 = new Thread(ticket);
Thread t3 = new Thread(ticket);
t1.start();
t2.start();
t3.start();
}
执行后的结果发现有的票被卖了两次,还卖了不存在的票。
解决方案,使用同步代码块。
public class Ticket implements Runnable{
private int tickets = 100;
Object o = new Object();
public void run() {
synchronized (o) {
while(true) {
if(tickets > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("正在卖第" + tickets-- + "张票");
}else
System.exit(0);
}
}
}
}
当然还可以使用同步方法。
public class Ticket implements Runnable{
private int tickets = 100;
Object o = new Object();
public void run() {
extracted();
}
private synchronized void extracted() {
while(true) {
if(tickets > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("正在卖第" + tickets-- + "张票");
}else
System.exit(0);
}
}
}
这个时候锁的是当前对象this。如果方法是static的,锁此类的字节码对象。