创建多线程两种方式:
1,继承Thread类,并重写该类的run方法。
2,实现Runnable接口。重写run方法。举例:SecondThread extends Runnable
SecondThread st=new SecondThread();
new Thread(st,"one").start();
new Thread(st,"two").start();
区别:
使用继承 Thread类获取当前线程对象比较简单,直接使用this就可以了;但使用实现Runnable接口时要获得当前线程对象必须使用Thread.currentThread()方法
采用Runnable接口的多条线程可以共享线程类的实例属性。因为他们共享传入的对象。例如:上面共享st对象。
目前都采用实现Runnable接口的方式。
状态:新建,就绪,运行,阻塞,死亡
从阻塞状态只能进入就绪状态,然后才是运行
控制线程:
1,join。当执行中调用了其他线程的join方法。那么本线程会阻塞,直到被调用的线程执行完成。
2,后台线程。当所有前台线程死亡,后台线程会自动死亡。调用Thread对象的setDaemon(true)就可以设置成后台线程。
3,线程睡眠sleep,线程进入阻塞
4,线程让步yield,线程进入就绪,完全可能,线程调度器马上将其调度重新执行。只有优先级与当前线程相同,或者优先级比当前线程更高的就绪状态的线程才会获得执行的机会
5,线程同步:
一同步监视器
1,使用同步监视器的通用方法就是同步代码块。
synchronized(obj)
{
}
上面obj就是同步监视器。线程开始执行同步代码块前,必须先获得对同步监视器的锁定。
2,同步方法
使用synchronized修饰方法。无须指定同步监视器。同步方法的同步监视器是this,也就是该对象本身。
不可变类总是线程安全的。因为它的对象的状态不可改变。可变类,例如银行账户中钱属性,当两线程同时修改,就异常了。所以只要将修改钱的方法设置成同步方法,那么
安全了。public synchronized void draw(double drawAmount)
二,同步锁
使用锁对象,通常 使用ReentrantLock(可重入锁),使用该lock对象可以显示加锁,释放锁
class X{
private final ReentrantLock lock=new ReentrantLock();
public void m(){
lock.lock();
try{
}
finally{
lock.unlock();
}
}
}
6,线程通信
1,同步监视器协调运行
借助object类提供的wait,notify,notifyAll方法。这3个方法必须由同步监视器对象来调用。
两种情况:同步方法,因为默认实例就是同步监视器,所以直接调用这三个方法
同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用该对象调用这三个方法。
2,Condition类协调
当使用Lock对象来保证同步,则系统没有同步监视器对象。所以用condition类。,
Condition将同步监视器方法(wait,notify,notifyAll)分解成不同对象,与Lock对象组合使用。在这种情况下,lock替代同步方法,condition代替
同步监视器的功能。
实例实际上被绑定到一个Lock对象上。要获得Lock实例的Condition对象,调用Lock对象的newCondition方法。
Callable和Future
可能受C#(C#可以把任何方法包装成线程执行体,包括有返回值的方法)的启发。从jdk1.5开始,java提供Callable接口,该接口提供call方法作为执行体,但
call方法更强大:
call方法可以有返回值
call可以声明抛出异常
Future接口代表Call方法的返回值,并为future接口提供一个实现类FutureTask,该类还实现了Runnable接口--可以作为Thread类的target。
class RtnThread implements Callable<Integer>
RtnThread rt=new RtnThread();
FutureTask<Integer> task=new FutureTask<Ingeger>(rt);
new Thread(task,"name").start
线程池
Executors类