Java使用thread类代表线程,所有的线程对象都必须是thread类或是thread类或其子类的实例。每个线程的作用是完成一定的任务,实际就是执行一段程序流(一段顺序执行的代码)。Java使用线程执行体来代表这段程序流。
线程的创建
继承thread类创建线程类
通过继承thread类来创建并启动多线程的步骤如下:
1、定义thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务。因此把run()方法称为线程执行体。
2、创建thread子类的实例,即创建了线程对象。
3、调用线程对象的start()方法启动该线程。
class MyThread extends Thread{
private static int num = 0;
public MyThread(){
num++;
}
@Override
public void run() {
System.out.println("主动创建的第"+num+"个线程");
}
}
实现runnable接口创建线程类
实现runnable接口来创建并启动多线程的步骤如下:
1、定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法同样是该线程的线程执行体。
2、创建runnable实现类的实例,并以此实例作为thread的target来创建thread对象,该thread对象才是真正的线程对象。
public class Test {
public static void main(String[] args) {
System.out.println("主线程ID:"+Thread.currentThread().getId());
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
class MyRunnable implements Runnable{
public MyRunnable() {
}
@Override
public void run() {
System.out.println("子线程ID:"+Thread.currentThread().getId());
}
}
线程的生命周期
新建和就绪状态
实现Runnable接口和继承Thread可以得到一个线程类,new一个实例出来,线程就进入了新建状态。
当线程对象调用了start()方法之后,该线程处于就绪状态。
运行和阻塞状态
如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程就处于运行状态。
阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。阻塞有两种,一种是sleep()方法,这种方法不会释放锁。另一种是wait()方法会释放锁。
线程死亡
线程有三种方式结束:
run()或call()方法执行完成,线程正常结束
线程抛出异常或错误
直接调用线程的stop()方法来结束该线程(该方法容易造成死锁)
线程同步
Java所有对象都有一个内置锁,使用 synchronized 关键字修饰方法或代码块时将为当前对象加锁,一个线程获取锁后,其他线程需要等待该线程执行完毕后解锁。
synchronized方法和synchronized代码块
public class SynchronizedThread {
class Bank {
private int account = 100;
public int getAccount() {
return account;
}
// 用同步方法实现
public synchronized void save(int money) {
account += money;
}
// 用同步代码块实现
public void save1(int money) {
synchronized (this) {
account += money;
}
}
}
同步锁(lock)
class Bank {
private int account = 100;
//需要声明这个锁
private Lock lock = new ReentrantLock();
public int getAccount() {
return account;
}
//这里不再需要synchronized
public void save(int money) {
lock.lock();
try{
account += money;
}finally{
lock.unlock();
}
}
}