线程的实现方式:
a.继承Thread类,重写run方法
Thread类:
所属包:java.lang;
构造方法:
public Thread();
public Thread(String name);
public Thread(Runnable target);
public Thread(Runnable target,String name);
静态方法:
static Thread currentThread();//获取当前线程
static void sleep(long millis);//让线程休息millis毫秒
成员变量:
private Runnable target;
成员方法:
void start();//启动线程(只能调用一次,不能调用多次)
void run(){};//线程启动后执行run方法
String getName();//获取线程名字
void setName(String name);//设置线程名字
public class MyThread extends Thread{
@Override
public void run() {
super.run();
System.out.println("继承Thread类实现run方法");
}
public static void main(String[] args) {
MyThread th = new MyThread();
th.start();
}
b.实现Runnable接口,实现run方法
Runnable接口:
public abstract void run()
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("实现runnable类接口");
}
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
//创建线程
Thread th = new Thread(runnable);
th.start();
}
c.使用匿名内部类创建Callable方法,重写call方法
Callable<T>接口:
T call();
Callable<String> c = new Callable<String>() {
@Override
public String call() throws Exception {
//call方法中的代码是某个子线程执行的
System.out.println(Thread.currentThread().getName());
Thread.sleep(500);
return "test callable";
}
};
//创建一个固定线程池对象
ExecutorService es = Executors.newFixedThreadPool(2);
Future<String> future = es.submit(c);
//这行代码是主线程执行的
String result = future.get();
System.out.println(result);
//关闭线程池
es.shutdown();
d.创建线程池
Executors类:
static ExecutorService newFiexdThredadPool(int nThread);
ExecutorService接口:
void execute(Runnable r);//执行任务
<T> Future<T> submit(Callable<T> c);
Future<?> submit(Runnable r);
void shutdown();//关闭线程池
Future<T>接口
T get();//必须等子线程把任务执行完成,return以后才可以获取返回的结果。
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//创建一个固定线程池对象
ExecutorService es = Executors.newFixedThreadPool(2);
//执行任务
es.execute(r);
es.execute(r);
es.execute(r);
//关闭线程池
es.shutdown();
执行任务使用Runnable的方式和Thread的方式区别:建议使用Runnable
a.可以避免Java单继承的局限性
b.解耦合,任务和线程分离,提高代码的健壮性
c.线程池里面,只能传入Runnable或者Callable类型的对象,不用new Thread
线程池的使用好处:
1.提高响应速度。预先创建好了线程,只等任务过来执行。
2.降低资源消耗。线程池中的线程,执行完任务后,又返回到线程池中,下一个任务到来后 可以继续使用该线程。
3.提高线程的可管理性。一个线程大约需要消耗1M的空间,线程池可以设置最大线程的数 量。
线程安全:
线程安全的前提:多个线程访问同一资源,有可能产生线程安全问题
解决线程安全问题的三种方式:
synchronized代码块:
语法:
synchronized(锁对象){
//有可能发生线程安全问题的代码
}
synchronized方法:synchronized关键字写在返回值之前
静态:static修饰的方法。锁对象:当前类的反射对象。 Class 对象名 = 类名.class;
非静态:非static修饰的方法。锁对象:this
Lock接口:
void lock();
void unlock();
常用的实现类:ReentrantLock
构造方法:
public ReentrantLock();
synchronized:执行完大括号中的代码后,会自动释放锁。
synchronized代码块或者方法中发生异常后会不会释放锁对象:会释放锁对象
Lock:必须手动的调用unlock方法才能释放锁。
Lock锁,发生异常后不会自动释放,所以建议把手动释放锁的代码写在finally块中
线程的状态:
NEW:新建状态。一个线程创建以后,启动之前,就处于该状态。
Thread t=new Thread();
State s = t.getState();
System.out.println(s);//NEW新建状态
TERMINATED:消亡状态。线程执行完任务后,处于该状态。
RUNNABLE:可运行状态。线程正在整型任务,就处于该状态
BLOCKED:阻塞状态。获取synchronized锁对象失败,处于该状态
Runnable r=new Runnable() {
@Override
public void run() {
synchronized (this) {
for(;;);
}
}
};
Thread t1 = new Thread(r);
t1.start();
Thread t2 = new Thread(r);
t2.start();
Thread.sleep(100);//100毫秒保证两个子线程已经启动,并开始执行代码了
//获取并打印线程的状态
System.out.println(t1.getState());
System.out.println(t2.getState());
//获取了锁对象开始执行for循环的线程处于RUNNABLE状态
//没有获取锁对象的线程处于BLOCKED状态。
WAITING:无限等待状态。获取Lock锁对象失败,就处于该状态
Lock lock=new ReentrantLock();
Runnable r=new Runnable() {
@Override
public void run() {
lock.lock();
for(;;);
}
};
Thread t1=new Thread(r);
t1.start();
Thread t2=new Thread(r);
t2.start();
//100毫秒内保证两个子线程开始执行任务
Thread.sleep(100);
System.out.println(t1.getState());
System.out.println(t2.getState());
//获取了锁对象开始执行for循环的线程处于RUNNABLE状态
//没有获取Lock锁对象的线程处于WAITING状态。
TIMED_WAITING:计时等待状态。执行sleep方法,就处于该状态。