多线程学习2

多个线程间协作和通信

每个线程有自己栈空间,孤立运行,对我们没有价值。如果多个线程能够相互配合完成工作,这将会带来巨大的价值。线程与线程之间不是相互独立的个体,它们彼此之间需要相互通信和协作。

volatile

多个线程同时访问一个共享的变量的时候,每个线程的工作内存有这个变量的一个拷贝,变量本身还是保存在共享内存中。

Violate修饰字段,对这个变量的访问必须要从共享内存刷新一次。最新的修改写回共享内存。可以保证字段的可见性。绝对不是线程安全的,没有操作的原子性

适用场景:1、一个线程写,多个线程读;2、volatile变量的变化很固定

synchronized

关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性,又称为内置锁机制。

Synchronized的类锁和对象锁,本质上是两把锁,类锁实际锁的是每一个类的class对象。对象锁锁的是当前对象实例。

等待和通知机制

等待方原则:

1、获取对象锁

2、如果条件不满足,调用对象的wait方法,被通知后依然要检查条件是否满足

3、条件满足以后,才能执行相关的业务逻辑

Synchronized(对象){

While(条件不满足){

对象.wait()

}

业务逻辑处理

}

通知方原则:

1、 获得对象的锁;

2、 改变条件;

3、 通知所有等待在对象的线程

Synchronized(对象){

业务逻辑处理,改变条件

对象.notify/notifyAll

}

实例

public class Test {
    public static Object object = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();

        thread1.start();

        Thread.sleep(2000);

        thread2.start();
    }

    static class Thread1 extends Thread {
        @Override
        public void run() {
            synchronized (object) {
                System.out.println("线程" + Thread.currentThread().getName()
                        + "获取到了锁...");
                try {
                    System.out.println("线程" + Thread.currentThread().getName()
                            + "阻塞并释放锁...");
                    object.wait();
                } catch (InterruptedException e) {
                }
                System.out.println("线程" + Thread.currentThread().getName()
                        + "执行完成...");
            }
        }
    }

    static class Thread2 extends Thread {
        @Override
        public void run() {
            synchronized (object) {
                System.out.println("线程" + Thread.currentThread().getName()
                        + "获取到了锁...");
                object.notify();
                System.out.println("线程" + Thread.currentThread().getName()
                        + "唤醒了正在wait的线程...");
            }
            System.out
                    .println("线程" + Thread.currentThread().getName() + "执行完成...");
        }
    }
}/* Output: 
        线程Thread-0获取到了锁...
        线程Thread-0阻塞并释放锁...
        线程Thread-1获取到了锁...
        线程Thread-1唤醒了正在wait的线程...
        线程Thread-1执行完成...
        线程Thread-0执行完成...

join方法

线程A,执行了thread.join(),线程A等待thread线程终止了以后,A在join后面的语句才会继续执行

 如果在线程a中执行t.join()方法,则a会等t线程执行完之后再执行t.join后的代码。换句话说,谁用obj.join()方法,谁就有执行权限,会一直执行完任务。但前提是必须能够拿到线程obj对象的锁。

join的JDK代码:

public final void join() throws InterruptedException {  
    join(0);  
}  

就是说如果是t.join() = t.join(0) 0 JDK这样说的 A timeout of 0 means to wait forever 字面意思是永远等待,其实是等到t结束后。

/** 
 * Waits at most {@code millis} milliseconds for this thread to 
 * die. A timeout of {@code 0} means to wait forever. 
 * 
 * <p> This implementation uses a loop of {@code this.wait} calls 
 * conditioned on {@code this.isAlive}. As a thread terminates the 
 * {@code this.notifyAll} method is invoked. It is recommended that 
 * applications not use {@code wait}, {@code notify}, or 
 * {@code notifyAll} on {@code Thread} instances. 
 * 
 * @param  millis 
 *         the time to wait in milliseconds 
 * 
 * @throws  IllegalArgumentException 
 *          if the value of {@code millis} is negative 
 * 
 * @throws  InterruptedException 
 *          if any thread has interrupted the current thread. The 
 *          <i>interrupted status</i> of the current thread is 
 *          cleared when this exception is thrown. 
 */  
public final synchronized void join(long millis)  
throws InterruptedException {  
    long base = System.currentTimeMillis();  
    long now = 0;  
  
    if (millis < 0) {  
        throw new IllegalArgumentException("timeout value is negative");  
    }  
  
    if (millis == 0) {  
        while (isAlive()) {  
            wait(0);  
        }  
    } else {  
        while (isAlive()) {  
            long delay = millis - now;  
            if (delay <= 0) {  
                break;  
            }  
            wait(delay);  
            now = System.currentTimeMillis() - base;  
        }  
    }  
}  

Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程,比如退出后。

ThreadLocal

本质是个map,map的键就是每个线程对象,值就是每个线程所拥有的值

常用方法:

initialValue()

get()

set()

remove():将当前线程局部变量的值删除,这个方法是JDK 5.0新增的方法。当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

ThreadLocal拥有的这个变量,在线程之间很独立的,相互之间没有联系。内存占用相对来说比较大。

猜你喜欢

转载自my.oschina.net/u/3647713/blog/1790356