volatile和synchronized关键字
- Java支持多线程来访问一个对象或对象的成员变量
- 但由于每个线程都有一份这个对象的拷贝,所以程序执行时,每个线程看到的变量不一定是最新的(对象和成员变量虽然放在共享内存中,但是多核处理器为了加快程序的执行,允许每个线程有一份自己的拷贝)
- volatile关键字要求每一个线程对变量的访问和修改都在共享内存中,即每一次修改,所有的线程都可以看到
- 过多的使用volatile会降低程序效率,偶尔一用可以
- synchronized以修饰方法或者同步代码块的形式使用
- synchronized可以保证同一时刻,只有一个线程在执行同步方法或者同步代码块,有效保证了线程安全
- 无论是同步方法还是同步代码块,实现原理都是对监视器(monitor)的获取
- 线程获取锁,先执行monitorenter(监视器进入)指令,执行成功就是获取锁成功.释放锁时需要执行monitorexit(监视器退出)指令
- 获取监视器的过程具有排他性,即同一时刻,只能一个线程能获取到synchronized对象的监视器
- 线程只有先获取到synchronized对象监视器,才能进入到同步方法或同步代码块中,如果没有获取到,会在方法/块的入口处陷入阻塞状态
等待/通知机制
- 等待通知机制:A线程调用对象O的wait方法进入等待,B线程调用O的notify/notifyAll方法来通知线程A,线程A从等待状态退出,继续执行操作.两个线程通过对象O的交互过程就是等待通知机制
- A线程修改对象的值,B线程察觉到了值的变化,进行了响应的操作。这个模式就是生产者消费者模式.前者是生产者,后者是消费者.这种模式有效的实现了代码解耦
- 等待通知的相关方法,比如
notify()
、norityAll()
、wait()
方法被定义在Object中,任何一个Java对象都具有
等待/通知经典范式
等待线程(消费者):
synchronized(某对象){
while( 不满足条件 ){
对象.wait();
}
//如果满足,开始处理
}
通知线程(生产者):
synchronized(对象){
改变条件;
对象.notifyAll();//或者notify()方法
}
管道输入输出流(Piped)
- 专门读取线程数据
- 字节流:PipedOutputStream、PipedInputStream
- 字符流:PipedReader、PiedWriter
- Piped流的使用必须先进行连接:调用connect()方法
public static void main(String[] args) throws Exception{
PipedWriter out=new PipedWriter();
PipedReader in=new PipedReader();
//将输入输出进行连接,否则抛出IO异常
out.connect(in);
Thread p=new Thread(new Print(in),"p1");
p.start();
int receive=0;
while((receive=in.read())!=-1){
out.write(receive);
}
out.close();
}
static class Print implements Runnable{
private PipedReader in;
public Print(PipedReader in){
this.in=in;
}
public void run(){
int receive=0;
try{
while ((receive=in.read())!=-1){
System.out.println((char)receive);
}
}catch (IOException e){
}
}
}
Thread.join()
- 线程A调用线程B的join方法:线程A等待线程B终止后再继续执行.
- 超时等待join(long mills),给定时间内如果线程B没有终止,就不再等待
public static void main(String[] args) throws Exception{
Thread pre=Thread.currentThread();
for(int i=0;i<10;i++){
//每个线程有前一个线程的引用,等待前一个线程终止,才能返回
Thread thread=new Thread(new Domin(pre),String.valueOf(i));
thread.start();
pre=thread;
}
TimeUnit.SECONDS.sleep(5);
System.out.println("线程"+Thread.currentThread().getName()+"终止");
}
static class Domin implements Runnable{
private Thread thread;
public Domin(Thread thread){
this.thread=thread;
}
@Override
public void run(){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程是"+Thread.currentThread().getName()+"终止");
}
}
结果:
线程main终止
当前线程是0终止
当前线程是1终止
当前线程是2终止
当前线程是3终止
当前线程是4终止
当前线程是5终止
当前线程是6终止
当前线程是7终止
当前线程是8终止
f当前线程是9终止