线程
1、实现方式
2、生命周期
3、控制线程
4、线程同步三种方式
5、死锁
6、线程通信
7、线程组
8、自定义线程处理类
9、ThreadLocal<T>
10、线程不安全集合的包装与线程安全的集合
1、线程实现的三种方式:
方式1:覆写Thread的run方法
new Thread(){
@Override
public void run() {
}
}.start();
方式2:将Runnbale对象作为Thread的target
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
查看Thread源码,发现target,在构造方法中被赋值,在run方法中调用target的run方法。
Runnable target;
public void run() {
if (target != null) {
target.run();
}
}
方式3:使用FutureTask,它实现Runnable接口和Callable<V>接口,所以可以作为Thread的target,当run方法执行的时候,调用Callable的call方法,
FutureTask这样就封装了一个有返回值的线程任务,并且封装了public boolean cancel(boolean mayInterruptIfRunning)方法
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
return "futureTask";
}
});
new Thread(futureTask).start();
FutureTask是Runnable的实现类,封装一个有返回值有cancel方法的类。这样在线程中调用call方法之后就可以有返回值了。
2、线程生命周期
线程对象new->进入新建状态--如果调用start方法->就绪准备状态--如果被CPU调度执行->运行状态--之后可能进入阻塞状态
再进入就绪状态,也可能直接返回就绪状态,或者进入死亡状态。
a、进入阻塞状态的情况
》调用sleep方法,主动放弃所占有的资源。
》调用了一个阻塞式的IO方法,在方法返回之前,自己被阻塞
》试图获取一个同步锁的时候,等待别的线程释放锁,处于阻塞状态
》调用了wait方法,等待被唤醒期间处于阻塞状态
》调用了线程的suspend方法,该方法容易造成死锁,尽量勿用。
b、阻塞结束,再次进入就绪状态的情况
》sleep的时间结束
》IO方法返回
》拿到锁
》调用wait的对象调用了notify方法
》调用线程的resume方法
3、线程控制的五个方法
3.1、join():如果线程A在执行的时候,调用了线程B的join,那么线程A将等待线程B执行完之后,自己才会继续往下执行。
join(long millis),等待线程B执行的最大时间,如果超过这个时间线程B还没有执行完,就不再等待。
3.2、后台线程setDaemon
在a线程中,创建一个线程b
在线程a调用start方法之前,调用setDaemon(true),将a线程设置成为b的后台线程
当b线程死亡的时候,a线程会跟随b一起死亡。
3.3、sleep(long millis) 线程睡眠一段时间,如果它拥有锁,它sleep期间是不会释放锁的。
3.4、yield线程让步,让优先级比自己高的线程先执行
3.5、setPriority,设置线程的优先级
4、线程同步
4.1、锁方法,默认是锁住this对象,其它线程不能再同时锁住this对象
public synchronized void aa(){
}
//锁static方法,锁的是class对象
public static synchronized void aa(){
}
4.2、锁指定对象
public String test = "locked";
public void testLock(){
synchronized (test){
}
}
4.3、Lock对象,显示的调用 lock(),unlock()进行加锁和释放锁
5、死锁:当对象a的 a1方法加了锁,对象b的b1方法也加了锁
当线程t1和线程t2都可以访问对象a和b
当t1调用a对象的a1方法拿到锁,并且a1方法没有执行完,也就是没有释放a的锁,
这个时候由于某某原因线程t2抢到cpu资源,执行b对象的b1方法,拿到b对象的锁
在b1方法中调用a对象的a1方法,由于这个时候t1并没有释放锁,所以t2进入等待
在t2等待a对象锁的时候,t1抢占到cpu资源继续执行a1方法,这个时候a1方法去访问b对象的b1方法,
由于b对象的锁t2线程还没有释放,所以t1进入阻塞,等待b的锁
于是t1与t2进入死锁。
6、线程通信两种方式
6.1:synchronized来锁一个对象a,可以调用a对象的三个方法与其他线程通信
wait方法,当被锁的对象调用wait方法之后,当前线程会释放掉对象的锁,并且进入阻塞状态,等待被锁的该
notify方法,随机唤醒调用过a对象的wait方法而进入阻塞状态的一个线程
notifyAll方法,全部唤醒调用过a对象的wait方法而进入阻塞状态的线程
6.2 由于还可以使用lock对象来显示的作为一把锁,所以就使用Condition来显示的释放锁和唤醒其他等待线程
private Lock lock = new ReentrntLock();
private Condition condtiton = lock.newCondition();
通过lock对象来获得condtiton
condtiton.await()==wait一样的作用
condtiton.signal()==notify一样的作用
condtiton.signalAll()==notifyAll一样的作用
在生产与消费模式的时候,如果使用一个普通的list对象作为容器,当生产者先锁住list,然后再放入之前,发现list已经满了,调用list的wait,释放锁
并且调用notifyAll,来唤醒消费者线程进行消费,当消费者消费时候发现list如果是满的,就有可能有生成线程已经处于阻塞所以消费完之后,调用一下notify通知生成者
现在list已经有空余,可以生成了。
。当消费者线程发现list为空的时候,同样调用wait进入,阻塞,调用notifyAll,唤醒生产者进行生成。生产者生成完发现list为1,可能有消费者线程在等待,所以也notify一下。
java提供阻塞队列:
BlockQueue:
失败之后 抛出异常 返回false 阻塞线程
添加 add offer put
删除 remove poll take
获取元素 element peek 无
7、线程组 ThreadGroup
ThreadGroup(String name)
线程得到所在线程组Thread.currentThread().getThreadGroup();
线程默认属于创建他的线程组
线程组ThreadGroup调用,interrupt中断组中所有线程,setDaemon设置整个线程组为后台线程。。。。
8、自定义线程处理类
Thread.currentThread().setUncaughtExceptionHandler(aa)当该线程异常时候,会回调这里,但是并不是tray catch的效果,程序只是
回调一下而已,还是会和正常的崩溃一样。
9、ThreadLocal<T>
ThreadLocal<Object> a = new ThreadLocal()把任意object对象封装成一个数据隔离的对象,每个线程访问a对象的时候,
都会复制一份a的值到自己的线程中,也就是各个线程都会自己拥有一个单独的a对象,互相不影响。
10、将集合封装成线程安全的
Collection提供的synchronized开头的方法。
1、实现方式
2、生命周期
3、控制线程
4、线程同步三种方式
5、死锁
6、线程通信
7、线程组
8、自定义线程处理类
9、ThreadLocal<T>
10、线程不安全集合的包装与线程安全的集合
1、线程实现的三种方式:
方式1:覆写Thread的run方法
new Thread(){
@Override
public void run() {
}
}.start();
方式2:将Runnbale对象作为Thread的target
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
查看Thread源码,发现target,在构造方法中被赋值,在run方法中调用target的run方法。
Runnable target;
public void run() {
if (target != null) {
target.run();
}
}
方式3:使用FutureTask,它实现Runnable接口和Callable<V>接口,所以可以作为Thread的target,当run方法执行的时候,调用Callable的call方法,
FutureTask这样就封装了一个有返回值的线程任务,并且封装了public boolean cancel(boolean mayInterruptIfRunning)方法
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
return "futureTask";
}
});
new Thread(futureTask).start();
FutureTask是Runnable的实现类,封装一个有返回值有cancel方法的类。这样在线程中调用call方法之后就可以有返回值了。
2、线程生命周期
线程对象new->进入新建状态--如果调用start方法->就绪准备状态--如果被CPU调度执行->运行状态--之后可能进入阻塞状态
再进入就绪状态,也可能直接返回就绪状态,或者进入死亡状态。
a、进入阻塞状态的情况
》调用sleep方法,主动放弃所占有的资源。
》调用了一个阻塞式的IO方法,在方法返回之前,自己被阻塞
》试图获取一个同步锁的时候,等待别的线程释放锁,处于阻塞状态
》调用了wait方法,等待被唤醒期间处于阻塞状态
》调用了线程的suspend方法,该方法容易造成死锁,尽量勿用。
b、阻塞结束,再次进入就绪状态的情况
》sleep的时间结束
》IO方法返回
》拿到锁
》调用wait的对象调用了notify方法
》调用线程的resume方法
3、线程控制的五个方法
3.1、join():如果线程A在执行的时候,调用了线程B的join,那么线程A将等待线程B执行完之后,自己才会继续往下执行。
join(long millis),等待线程B执行的最大时间,如果超过这个时间线程B还没有执行完,就不再等待。
3.2、后台线程setDaemon
在a线程中,创建一个线程b
在线程a调用start方法之前,调用setDaemon(true),将a线程设置成为b的后台线程
当b线程死亡的时候,a线程会跟随b一起死亡。
3.3、sleep(long millis) 线程睡眠一段时间,如果它拥有锁,它sleep期间是不会释放锁的。
3.4、yield线程让步,让优先级比自己高的线程先执行
3.5、setPriority,设置线程的优先级
4、线程同步
4.1、锁方法,默认是锁住this对象,其它线程不能再同时锁住this对象
public synchronized void aa(){
}
//锁static方法,锁的是class对象
public static synchronized void aa(){
}
4.2、锁指定对象
public String test = "locked";
public void testLock(){
synchronized (test){
}
}
4.3、Lock对象,显示的调用 lock(),unlock()进行加锁和释放锁
5、死锁:当对象a的 a1方法加了锁,对象b的b1方法也加了锁
当线程t1和线程t2都可以访问对象a和b
当t1调用a对象的a1方法拿到锁,并且a1方法没有执行完,也就是没有释放a的锁,
这个时候由于某某原因线程t2抢到cpu资源,执行b对象的b1方法,拿到b对象的锁
在b1方法中调用a对象的a1方法,由于这个时候t1并没有释放锁,所以t2进入等待
在t2等待a对象锁的时候,t1抢占到cpu资源继续执行a1方法,这个时候a1方法去访问b对象的b1方法,
由于b对象的锁t2线程还没有释放,所以t1进入阻塞,等待b的锁
于是t1与t2进入死锁。
6、线程通信两种方式
6.1:synchronized来锁一个对象a,可以调用a对象的三个方法与其他线程通信
wait方法,当被锁的对象调用wait方法之后,当前线程会释放掉对象的锁,并且进入阻塞状态,等待被锁的该
notify方法,随机唤醒调用过a对象的wait方法而进入阻塞状态的一个线程
notifyAll方法,全部唤醒调用过a对象的wait方法而进入阻塞状态的线程
6.2 由于还可以使用lock对象来显示的作为一把锁,所以就使用Condition来显示的释放锁和唤醒其他等待线程
private Lock lock = new ReentrntLock();
private Condition condtiton = lock.newCondition();
通过lock对象来获得condtiton
condtiton.await()==wait一样的作用
condtiton.signal()==notify一样的作用
condtiton.signalAll()==notifyAll一样的作用
在生产与消费模式的时候,如果使用一个普通的list对象作为容器,当生产者先锁住list,然后再放入之前,发现list已经满了,调用list的wait,释放锁
并且调用notifyAll,来唤醒消费者线程进行消费,当消费者消费时候发现list如果是满的,就有可能有生成线程已经处于阻塞所以消费完之后,调用一下notify通知生成者
现在list已经有空余,可以生成了。
。当消费者线程发现list为空的时候,同样调用wait进入,阻塞,调用notifyAll,唤醒生产者进行生成。生产者生成完发现list为1,可能有消费者线程在等待,所以也notify一下。
java提供阻塞队列:
BlockQueue:
失败之后 抛出异常 返回false 阻塞线程
添加 add offer put
删除 remove poll take
获取元素 element peek 无
7、线程组 ThreadGroup
ThreadGroup(String name)
线程得到所在线程组Thread.currentThread().getThreadGroup();
线程默认属于创建他的线程组
线程组ThreadGroup调用,interrupt中断组中所有线程,setDaemon设置整个线程组为后台线程。。。。
8、自定义线程处理类
Thread.currentThread().setUncaughtExceptionHandler(aa)当该线程异常时候,会回调这里,但是并不是tray catch的效果,程序只是
回调一下而已,还是会和正常的崩溃一样。
9、ThreadLocal<T>
ThreadLocal<Object> a = new ThreadLocal()把任意object对象封装成一个数据隔离的对象,每个线程访问a对象的时候,
都会复制一份a的值到自己的线程中,也就是各个线程都会自己拥有一个单独的a对象,互相不影响。
10、将集合封装成线程安全的
Collection提供的synchronized开头的方法。