可以在T1的start方法后添加T1.join方法,在T2的start方法后添加T2.join方法
例如
public class TestJoin{
public static void main(String[] args){
Thread t1 = new MyThread(“线程1”);
Thread t2 = new MyThread(“线程2”);
Thread t3 = new MyThread(“线程3”);
try{
//t1先启动
t1.start();
t1.join();
//t2
t2.start();
t2.join();
//t3
t3.start();
t3.join();
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}
Lock接口在多线程和并发编程中最大的优势就是它为读和写分别提供了锁,它满足你在例如ConcurrentHashMap这样的高性能数据结构和有条件的阻塞。而且,Lock接口可以通过lock和unlock方法,实现加锁和解锁,可以出现在不同的方法中,例如加锁可以出现登陆方法中,而解锁可以出现在登出方法中,
高效的缓存,可以使用juc的locks包下的ReadWriteLock接口,这个接口有一个实现类ReentrantReadWriteLock,这个实现类中维护了两个锁,读锁和写锁
最大的不同实现等待的时候,wait会释放同步锁,但是sleep会一直持有同步锁。wait常用于线程间的交互,sleep通常被用在暂停一个线程的执行,声明位置方面,sleep声明在Thread类中,而wait声明在Object类中
可以使用wait和notify实现简单的阻塞队列,当一个线程做完特定操作以后,wait这个线程,然后notify另一个线程,这个线程同样做完特定操作以后,wait掉,notify另一个线程,如果多线程组成的阻塞队列,那么可以对线程设置优先级,notify会优先唤醒优先级高的线程
一共三种方式
①声明一个类继承Thread类,然后重写run方法,然后调用该类的start方法开启线程
②实现Runable接口,重写该接口中抽象run方法,然后创建此类对象,将这个对象传入Thread构造器,实例化Thread对象,调用Thread对象的start方法开启线程
③实现Callable接口,实现call方法,然后叫这个对象传入FutrueTask构造器中,实例化FutrueTask对象,然后将FutrueTask对象传入Thread构造器中,实例化Thread对象,调用Thread对象可以开启线程
如果使用Lock作为同步锁,线程A在调用了lock方法加锁后,发生了异常,没有执行unlock,此时会出现死锁,这个的解决方法就是将unlock放在finally中