线程间通信

wait/notify机制

原理

拥有相同锁的线程才可以实现wait/notify 机制
wait 方法时Object 类的方法,它的作用是使当前执行wait 方法的线程等待,在wait 所在的代码处暂停执行,并释放锁,直到接到通知或者被中断为止。在调用wait 之前必须获得该对象的对象级别锁,即只能在同步方法或者同步代码块中调用wait 方法,通过通知机制使某个线程继续执行wait 后面的代码,对线程的选择是按照执行wait 方法的顺序确定的,并需要重新获得锁。如果调用wait 时没有锁,则抛出异常
notify方法也要在同步方法或者同步代码块中使用,在调用 之前线程必须获得锁,该方法用来通知那些可能等待该锁的其他线程,如果有多个线程等待,则按照执行wait 方法的顺序对处于wait 状态的线程发出一次通知,并使该线程重新获取锁。在执行notify 方法后,当前线程不会马上释放锁,呈wait 状态的线程也不能马上获取该对象锁,要等到执行notify 方法的线程执行完,也就是退出synchronized 同步代码块后,当前线程才会释放锁,当第一个获得了该对象的wait 线程运行完毕后,它会释放锁,如果此时没有再次使用notify 语句,那么其他呈wait 状态的线程因为没有得到通知,会继续处于wait 状态
总结:wait 方法使线程暂停运行,notify 方法通知暂停线程继续运行

wait / notify 方法的基本使用

package P193;

import javafx.beans.binding.ObjectExpression;
import jdk.nashorn.internal.ir.CatchNode;

public class MyThread1 extends Thread {
    private Object lock;
    public MyThread1(Object object){
        super();
        this.lock=object;
    }

    @Override
    public void run() {
        super.run();
        try {
            synchronized (lock) {
                System.out.println("begin ,wait time=" + System.currentTimeMillis());
                lock.wait();
                System.out.println("end ,wait time=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

package P193;

import javafx.beans.binding.ObjectExpression;

public class MyThread2 extends Thread {
    private Object lock;
    public MyThread2(Object lock){
        this.lock=lock;
    }

    @Override
    public void run() {
        super.run();
        synchronized (lock){
            System.out.println("begin ,notify time="+System.currentTimeMillis());
            lock.notify();
            System.out.println("end ,notify time="+System.currentTimeMillis());
        }
    }
}

package P193;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        MyThread1 myThread1 = new MyThread1(lock);
        MyThread2 myThread2 = new MyThread2(lock);
        myThread1.start();
        Thread.sleep(3000);
        myThread2.start();
    }
}

在这里插入图片描述

线程状态的切换

  • 创建
    new Thread()
  • 就绪
    新建线程调用start 方法后进入就绪状态,如果线程抢到CPU资源,线程就进入运行状态
    线程进入就绪状态可分为如下4种情况:
  1. 调用sleep方法后经过的时间超过了指定的休眠时间
  2. 线程获得了试图同步的监视器
  3. 线程正在等某个通知,其他线程发出了通知
  4. 处于挂起的线程调用了resume方法
  • 运行
    运行run 方法
  • 阻塞
    出现阻塞分为如下5种:
  1. 线程调用sleep方法,主动放弃占用的处理器资源
  2. 线程调用了阻塞式I/O方法,在该方法返回前,该线程被阻塞
  3. 线程试图获得一个同步监视器,但该监视器正在被其他线程所持有
  4. 线程等待某个notify
  5. 程序调用了suspend方法,该方法容易导致死锁,尽量避免使用
  • 销毁
    run方法运行结束后进入销毁阶段,整个线程执行完毕

notify 和 notifyAll

每调用一次notify 方法,只通知一个线程进行唤醒,环形的顺序和执行wait 方法的顺序一致;notifyAll 方法会执行wait 方法的倒序依次对其他线程进行唤醒

wait(long)

wait(long) 的功能使等待某一时间内是否有线程对所进行notify 通知唤醒,如果超过这个时间则线程自动唤醒,能继续向下运行的前提使再次持有锁

package P213;

import com.sun.corba.se.impl.orbutil.CacheTable;
import com.sun.xml.internal.bind.v2.model.annotation.RuntimeAnnotationReader;

import javax.naming.event.ObjectChangeListener;
import java.util.PrimitiveIterator;

public class MyRunnable {
    static private Object lock=new Object();
    static private Runnable runnable=new Runnable() {
        @Override
        public void run() {
            try {
                synchronized (lock){
                    System.out.println("wait begin timer="+System.currentTimeMillis());
                    lock.wait(5000);
                    System.out.println("wait end timer="+System.currentTimeMillis());
                }
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    };

    public static void main(String[] args) {
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

在这里插入图片描述

生产者和消费者模式

单生产和单消费:操作值

package P225;

public class ValueObject {
    public static String value="";
}

package P225;

import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo;
import sun.awt.SunHints;

public class P {
    private Object lock;
    public P(Object lock){
        this.lock=lock;
    }
    public void setValue(){
        try{
            synchronized (lock){
                if(!ValueObject.value.equals("")){
                    lock.wait();
                }
                String value=System.currentTimeMillis()+"_"+System.nanoTime();
                System.out.println("set的值是:"+value);
                ValueObject.value=value;
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P225;

import sun.awt.SunHints;

public class C {
    private Object lock;
    public C(Object lock){
        this.lock=lock;
    }
    public void getValue(){
        try{
            synchronized (lock){
                if(ValueObject.value.equals("")){
                    lock.wait();
                }
                System.out.println("get的值为:"+ValueObject.value);
                ValueObject.value="";
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P225;

public class Pthread extends Thread {
    private P p;
    public Pthread(P p){
        this.p=p;
    }

    @Override
    public void run() {
        while(true){
            p.setValue();
        }
    }
}

package P225;

public class Cthread extends Thread {
    private C c;
    public Cthread(C c){
        this.c=c;
    }

    @Override
    public void run() {
        while(true){
            c.getValue();
        }
    }
}

package P225;

import javax.naming.event.ObjectChangeListener;

public class Run {
    public static void main(String[] args) {
        Object object=(Object) new String("");
        C c = new C(object);
        P p = new P(object);
        Pthread pthread = new Pthread(p);
        Cthread cthread = new Cthread(c);
        pthread.start();
        cthread.start();
    }
}

在这里插入图片描述

多生产和多消费:操作值(假死)

“假死”现象就是线程全部进入等待状态,整个项目呈停止状态,不能继续运行下去,原因在于可能生产者或消费者连续唤醒同类,解决方法是将notify 替换为 notifyAll

package P231;

public class ValueObject {
    public static String value="";
}

package P231;

public class P {
    private Object lock;
    public P(Object lock){
        this.lock=lock;
    }

    public void setValue(){
        try{
            synchronized (lock){
                while(!ValueObject.value.equals("")){
                    System.out.println("生产者 "+Thread.currentThread().getName()+" WAITING***");
                    lock.wait();
                }
                System.out.println("生产者 "+Thread.currentThread().getName()+" RUNNING-----");
                String value=System.currentTimeMillis()+"--"+System.nanoTime();
                ValueObject.value=value;
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P231;

public class C {
    private Object lock;
    public C(Object lock){
        this.lock=lock;
    }
    public void getValue(){
        try{
            synchronized (lock){
                while(ValueObject.value.equals("")){
                    System.out.println("消费者  "+Thread.currentThread().getName()+"  WAITING***");
                    lock.wait();
                }
                System.out.println("消费者  "+Thread.currentThread().getName()+"  RUNNING");
                ValueObject.value="";
                lock.notify();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P231;

public class Pthread extends Thread {
    private P p;
    public Pthread(P p){
        this.p=p;
    }

    @Override
    public void run() {
        while(true){
            p.setValue();
        }
    }
}

package P231;

public class Cthread extends Thread {
    private C c;
    public Cthread(C c){
        this.c=c;
    }

    @Override
    public void run() {
        while(true){
            c.getValue();
        }
    }
}

package P231;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Object lock = (Object) new String("");
        P p = new P(lock);
        C c = new C(lock);
        Pthread[] pthreads=new Pthread[2];
        Cthread[] cthreads = new Cthread[2];

        for (int i = 0; i < 2; i++) {
            pthreads[i]=new Pthread(p);
            cthreads[i]=new Cthread(c);

            pthreads[i].setName("生产者"+i);
            cthreads[i].setName("消费者"+i);

            pthreads[i].start();
            cthreads[i].start();
        }
    }
}

在这里插入图片描述

单生产与多消费:操作栈

生产者想堆栈List对象种放入数据,使用多个消费者从List堆栈中取出数据,假设List的最大容量为1

package P233;

import jdk.nashorn.internal.runtime.linker.LinkerCallSite;

import java.beans.IntrospectionException;
import java.util.ArrayList;
import java.util.List;
import java.util.PrimitiveIterator;

public class MyStack {
    private List list=new ArrayList();

    public void push(){
        try {
            synchronized (this){
                if(list.size()==1){
                    this.wait();
                }
                list.add("anything="+ Math.random());
                this.notify();
                System.out.println("Push="+list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void pop(){
        try{
            synchronized (this){
                if(list.size()==0){
                    this.wait();
                }
                String value=" "+list.get(0);
                list.remove(0);
                this.notify();
                System.out.println("Pop="+list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P233;

import P193.MyThread2;
import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior;

import java.util.List;

public class Pthread extends Thread {
    private MyStack mystack;
    public Pthread(MyStack myStack){
        this.mystack= myStack;
    }

    @Override
    public void run() {
        while (true){
            mystack.push();
        }
    }
}

package P233;

public class Cthread extends Thread {
    private MyStack myStack;
    public Cthread(MyStack myStack){
        this.myStack=myStack;
    }

    @Override
    public void run() {
        while (true){
            myStack.pop();
        }
    }
}

package P233;

import java.awt.*;
import java.util.ArrayList;

public class Run {
    public static void main(String[] args) {
        MyStack myStack=new MyStack();
        Pthread pthread = new Pthread(myStack);
        Cthread cthread = new Cthread(myStack);
        pthread.start();
        cthread.start();

    }
}

在这里插入图片描述

多生产与一消费:操作栈

package P233;

import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
import org.w3c.dom.ls.LSInput;

import java.beans.IntrospectionException;
import java.util.ArrayList;
import java.util.List;
import java.util.PrimitiveIterator;

public class MyStack {
    private List list=new ArrayList();

    public void push(){
        try {
            synchronized (this){
                while(list.size()==1){
                    this.wait();
                }
                list.add("anything="+ Math.random());
                this.notifyAll();
                System.out.println("Push="+list.size()+"  "+Thread.currentThread().getName()+"  "+ list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void pop(){
        try{
            synchronized (this){
                while(list.size()==0){
                    this.wait();
                }
                String value=" "+list.get(0);
                list.remove(0);
                this.notifyAll();
                System.out.println("Pop="+list.size()+" "+Thread.currentThread().getName()+"  "+list.size());
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P233;

public class Cthread extends Thread {
    private MyStack myStack;
    public Cthread(MyStack myStack){
        this.myStack=myStack;
    }

    @Override
    public void run() {
        while (true){
            myStack.pop();
        }
    }
}

package P233;

import P193.MyThread2;
import com.sun.javafx.scene.control.behavior.TwoLevelFocusPopupBehavior;

import java.util.List;

public class Pthread extends Thread {
    private MyStack mystack;
    public Pthread(MyStack myStack){
        this.mystack= myStack;
    }

    @Override
    public void run() {
        while (true){
            mystack.push();
        }
    }
}

package P233;

import java.awt.*;
import java.util.ArrayList;

public class Run {
    public static void main(String[] args) {
        MyStack myStack=new MyStack();
        Pthread pthread1 = new Pthread(myStack);
        Pthread pthread2 = new Pthread(myStack);
        Pthread pthread3 = new Pthread(myStack);
        Pthread pthread4 = new Pthread(myStack);
        Cthread cthread = new Cthread(myStack);
        pthread1.start();
        pthread2.start();
        pthread3.start();
        pthread4.start();
        cthread.start();

    }
}

在这里插入图片描述

连续生产和连续消费

package P243;

import P139.ThreadA;
import sun.text.normalizer.UBiDiProps;

import java.util.ArrayList;
import java.util.List;

public class Box {
    public List list=new ArrayList();
    synchronized public void add(){
            try{
                while(list.size()==15){
                    this.wait();
                }
                Thread.sleep(500);
                list.add("angthing");
                this.notifyAll();
                System.out.println("线程:"+Thread.currentThread().getName()+"  "+"size="+list.size());
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
    }
    synchronized public void remove(){
            try{
                while(list.size()==0){
                    this.wait();
                }
                Thread.sleep(500);
                list.remove(0);
                this.notifyAll();
                System.out.println("线程:"+Thread.currentThread().getName()+"  "+"size="+list.size());
            }
            catch (InterruptedException e){
                e.printStackTrace();
            }
    }
}

package P243;

public class Pthread extends Thread {
    private Box box;
    public Pthread(Box box){
        this.box=box;
    }

    @Override
    public void run() {
        while (true){
            box.add();
        }
    }
}

package P243;

import com.sun.org.apache.xpath.internal.WhitespaceStrippingElementMatcher;

public class Cthread extends Thread {
    private Box box;
    public Cthread(Box box){
        this.box=box;
    }

    @Override
    public void run() {
        while(true){
            box.remove();
            Thread.yield();
        }
    }
}

package P243;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Box box = new Box();
        Pthread pthread1 = new Pthread(box);
        pthread1.setName("生产者1");
        Pthread pthread2 = new Pthread(box);
        pthread2.setName("生产者2");
        Cthread cthread1 = new Cthread(box);
        cthread1.setName("消费者1");
        pthread1.start();
        pthread2.start();
        cthread1.start();
    }
}

通过管道进行线程间通信

Java提供各种各样的输入输出流方便我们用于对数据的操作,其中管道流用于在不同线程间直接传送数据。一个线程发送数据到管道,另一个线程从输入管道中读数据,通过管道实现不同线程间的通信

字节流

PipedInputStream 和 PipedOutputStream


import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class Test {
        public static void main(String[] args) {
            PipedInputStream in = new PipedInputStream();
            PipedOutputStream out = new PipedOutputStream();
            try {
                in.connect(out);
                out.write("测试".getBytes("utf8"));
                out.close();
                byte[] bytes = new byte[100];
                in.read(bytes);
                System.out.println(new String(bytes, "utf8"));
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
}
package P251;

import java.io.IOException;
import java.io.PipedOutputStream;

public class WriteData {
    public void writeMethod(PipedOutputStream out) {
        try {
            System.out.println("write:");
            for (int i = 0; i < 100; i++) {
                String outData = "" + (i + 1);
                try {
                    out.write(outData.getBytes("utf8"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package P251;

import java.io.IOException;
import java.io.PipedInputStream;

public class ReadData {
    public void readMethod(PipedInputStream in){
        try{
            System.out.println("read:");
            byte[] bytes = new byte[20];
            int k=in.read(bytes);
            while(k!=-1){
                String s = new String(bytes, 0, k);
                System.out.println(s);
                k=in.read(bytes);
            }
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


package P251;

import java.io.PipedOutputStream;

public class WriteThread extends Thread {
    private WriteData writeData;
    private PipedOutputStream pipedOutputStream;
    public WriteThread(WriteData writeData,PipedOutputStream pipedOutputStream){
        this.writeData=writeData;
        this.pipedOutputStream=pipedOutputStream;
    }

    @Override
    public void run() {
        writeData.writeMethod(pipedOutputStream);
    }
}

package P251;

import java.io.PipedInputStream;

public class ReadThread extends Thread {
    private ReadData readData;
    private PipedInputStream pipedInputStream;
    public ReadThread(ReadData readData,PipedInputStream pipedInputStream){
        this.readData=readData;
        this.pipedInputStream=pipedInputStream;
    }

    @Override
    public void run() {
        readData.readMethod(pipedInputStream);
    }
}

package P251;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class Run {
    public static void main(String[] args) throws InterruptedException, IOException {
        WriteData writeData = new WriteData();
        ReadData readData = new ReadData();
        PipedInputStream pipedInputStream = new PipedInputStream();
        PipedOutputStream pipedOutputStream = new PipedOutputStream();

        pipedInputStream.connect(pipedOutputStream);

        ReadThread readThread = new ReadThread(readData, pipedInputStream);
        WriteThread writeThread = new WriteThread(writeData, pipedOutputStream );

        readThread.start();
        Thread.sleep(2000);
        writeThread.start();
    }
}

在这里插入图片描述

字符流

package P253;

import java.io.IOException;
import java.io.PipedWriter;

public class WriteData {
    public void writeMethod(PipedWriter out){
        System.out.println("write:");
        for(int i=0;i<100;i++){
            String data=""+(i+1);
            try {
                out.write(data);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package P253;

import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedReader;

public class ReadData {
    public void readMethod(PipedReader in){
        try{
            System.out.println("read:");
            char[] chars = new char[20];
            int k=in.read(chars);
            while(k!=-1){
                String s = new String(chars, 0, k);
                System.out.println(s);
                k=in.read(chars);
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }

    }
}

package P253;

import com.sun.corba.se.impl.ior.WireObjectKeyTemplate;

import java.io.PipedWriter;

public class Wthread extends Thread {
    private WriteData writeData;
    private PipedWriter pipedWriter;
    public Wthread(WriteData writeData,PipedWriter pipedWriter){
        this.writeData= writeData;
        this.pipedWriter=pipedWriter;
    }

    @Override
    public void run() {
        writeData.writeMethod(pipedWriter);
    }
}

package P253;

import java.io.PipedReader;

public class Rthread extends Thread {
    private ReadData readData;
    private PipedReader pipedReader;
    public Rthread(ReadData readData,PipedReader pipedReader){
        this.readData=readData;
        this.pipedReader=pipedReader;
    }

    @Override
    public void run() {
        readData.readMethod(pipedReader);
    }
}

package P253;

import P233.Pthread;

import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;

public class Run {
    public static void main(String[] args) throws InterruptedException, IOException {
        WriteData writeData = new WriteData();
        ReadData readData = new ReadData();
        PipedWriter pipedWriter = new PipedWriter();
        PipedReader pipedReader = new PipedReader();

        pipedReader.connect(pipedWriter);

        Wthread wthread = new Wthread(writeData, pipedWriter);
        Rthread rthread = new Rthread(readData, pipedReader);

        rthread.start();
        Thread.sleep(2000);
        wthread.start();
    }
}

在这里插入图片描述

wait/notify 实现循环打印

循环打印AB

package P257;

import sun.util.resources.cldr.de.CalendarData_de_AT;

import java.util.PrimitiveIterator;

public class Service {
    volatile private boolean printA=false;

    synchronized public void A(){
        try {
            while(printA==false){
                this.wait();
            }
            System.out.println("A"+'-'+Thread.currentThread().getName()+"  ");
            Thread.sleep(100);
            printA=false;
            this.notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public void B(){
        try {
            while(printA==true){
                this.wait();
            }
            System.out.println("B"+"-"+Thread.currentThread().getName()+"  ");
            Thread.sleep(100);
            printA=true;
            this.notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P257;

public class Athread extends Thread {
    private Service service;
    public Athread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while(true){
            service.A();
        }
    }
}

package P257;

import javax.swing.event.TreeWillExpandListener;

public class Bthread extends Thread {
    private Service service;
    public Bthread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.B();
        }
    }
}

package P257;

public class Run {
    public static void main(String[] args) {
        Service service = new Service();
        for (int i = 0; i < 2; i++) {
            Athread athread = new Athread(service);
            Bthread bthread = new Bthread(service);
            athread.start();
            bthread.start();
        }
    }
}

在这里插入图片描述

循环打印ABC

package PrintABC;

public class Service {
    volatile private boolean printA=true;
    volatile private boolean printB=false;
    volatile private boolean printC=false;

    synchronized public void printA(){
        try {
            while(printA==false){
                this.wait();
            }
            System.out.println("A");
            printA=false;
            printB=true;
            printC=false;
            Thread.sleep(100);
            notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public void printB(){
        try {
            while(printB==false){
                this.wait();
            }
            System.out.println("B");
            printA=false;
            printB=false;
            printC=true;
            Thread.sleep(100);
            notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public void printC(){
        try {
            while(printC==false){
                this.wait();
            }
            System.out.println("C");
            printA=true;
            printB=false;
            printC=false;
            Thread.sleep(100);
            notifyAll();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

}

package PrintABC;

public class Athread extends Thread {
    private Service service;
    public Athread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.printA();
        }
    }
}

package PrintABC;

import com.sun.xml.internal.ws.runtime.config.TubelineFeatureReader;

public class Bthread extends Thread {
    private Service service;
    public Bthread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.printB();
        }
    }
}

package PrintABC;

import javafx.scene.control.cell.CheckBoxTreeCell;

public class Cthread extends Thread {
    private Service service;
    public Cthread(Service service){
        this.service=service;
    }

    @Override
    public void run() {
        while (true){
            service.printC();
        }
    }
}

package PrintABC;

import P115.ThreadB;

import java.security.PublicKey;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Service service = new Service();

        Athread athread = new Athread(service);
        Bthread bthread = new Bthread(service);
        Cthread cthread = new Cthread(service);
        athread.start();
        Thread.sleep(2000);
        bthread.start();
        Thread.sleep(2000);
        cthread.start();
    }
}

在这里插入图片描述

join方法

join方法的作用是使所属的线程对象正常执行完run方法中的任务,而是当前线程进行无限期阻塞,等到线程销毁后再继续执行当前线程后面的代码,具有串联执行的效果

join

package P264;

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("run begin Time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("run end TImer="+System.currentTimeMillis());
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("main begin timer="+System.currentTimeMillis());
        myThread.join();
        System.out.println("main end timer="+System.currentTimeMillis());
    }
}

在这里插入图片描述

join(long)

package P264;

public class MyThread extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("run begin Time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("run end TImer="+System.currentTimeMillis());
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("main begin timer="+System.currentTimeMillis());
        myThread.join(2000);
        System.out.println("main end timer="+System.currentTimeMillis());
    }
}

在这里插入图片描述

join(long) 和 sleep(long) 区别

join(long)方法的功能是在内部使用wait(long)方法来进行实现的,所以join(long)方法具有释放锁的特点

sleep(long) 释放锁

package P265;

public class ThreadB extends Thread {
    @Override
    public void run() {
        try {
            System.out.println("b begin time="+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("b end time="+System.currentTimeMillis());
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized  public void bService(){
        System.out.println("打印bService time="+System.currentTimeMillis());
    }
}


package P265;

public class ThreadA extends Thread {
    private ThreadB threadB;
    public ThreadA(ThreadB threadB){
        this.threadB=threadB;
    }

    @Override
    public void run() {
        try {
            synchronized (threadB){
                threadB.start();
                Thread.sleep(6000);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P265;

public class ThreadC extends Thread {
    private ThreadB threadB;
    public ThreadC(ThreadB threadB){
        this.threadB=threadB;
    }

    @Override
    public void run() {
        threadB.bService();
    }
}

package P265;

public class Run {
    public static void main(String[] args) throws InterruptedException {
        ThreadB threadB = new ThreadB();
        ThreadA threadA = new ThreadA(threadB);
        threadA.start();
        Thread.sleep(1000);
        ThreadC threadC = new ThreadC(threadB);
        threadC.start();
    }
}

在这里插入图片描述

join(long) 释放锁

修改ThreadA的代码,其余不变;可见执行ThreadB.join() 后ThreadB的锁释放,原因是join方法的功能在内部是使用wait 方法来实现的,所以join方法释放锁

package P265;

public class ThreadA extends Thread {
    private ThreadB threadB;
    public ThreadA(ThreadB threadB){
        this.threadB=threadB;
    }

    @Override
    public void run() {
        try {
            synchronized (threadB){
                threadB.start();
                threadB.join();
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

类ThreadLocal 的使用

类ThreadLocal的主要作用是将当前线程的数据放入当前线程对象的Map中,这个Map是Thread类的实例变量。类ThreadLocal自己不管理、存储数据,它只是数据和Map中间的桥梁,用于将数据放入Map中。Map中的key存储的是ThreadLocal对象,value就是存储的值,每个线程中的Map值只对当前线程可见。

线程变量的隔离性

package P279;

public class Tools {
    public static ThreadLocal t1=new ThreadLocal();
}

package P279;

public class MyThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                Tools.t1.set("A"+(i+1));
                System.out.println("A get "+Tools.t1.get());
                int sleepValue=(int)(Math.random()*1000);
                Thread.sleep(sleepValue);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P279;

public class MyThreadB extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                Tools.t1.set("B"+(i+1));
                System.out.println("   B get "+ Tools.t1.get());
                int i1 = (int) (Math.random() * 1000);
                Thread.sleep(i1);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P279;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThreadA myThreadA = new MyThreadA();
        MyThreadB myThreadB = new MyThreadB();
        myThreadA.start();
        myThreadB.start();
        for (int i = 0; i < 10; i++) {
            Tools.t1.set("main  "+(i+1));
            System.out.println("      main get "+ Tools.t1.get());
            int sleepValue=(int)(Math.random()*1000);
            Thread.sleep(sleepValue);
        }
    }
}

在这里插入图片描述

get 方法

在第一次调用ThreadLocal 类的get 方法时,返回值为 null,可以通过继承ThreadLocal 类并重写里面的 initialValue 方法来改变get 的默认初值,该方法也具有隔离性

类InheritableThreadLocal 的使用

ThreadLocal 类不能实现子线程值继承

package P287;

public class Tools {
    public static ThreadLocal t1=new ThreadLocal();
}

package P287;

public class ThreadA extends Thread {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                System.out.println("在ThreaadA线程中取值:"+ Tools.t1.get());
                Thread.sleep(100);
            }
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

package P287;

public class Test {
    public static void main(String[] args) {
        try {
            for (int i = 0; i < 10; i++) {
                if(Tools.t1.get()==null){
                    Tools.t1.set("此值时main线程放入的");
                }
                System.out.println("      在main线程中取值="+ Tools.t1.get());
                Thread.sleep(100);
            }
            Thread.sleep(5000);
            ThreadA threadA = new ThreadA();
            threadA.start();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

InheritableThreadLocal 体现子线程值继承

将ThreadLocal改为inheritableThreadLocal类,子线程ThreadA线程获取的值是从父线程main继承来的
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值