《java多线程编程核心技术》第三章笔记

https://blog.csdn.net/a724888/article/details/60867081#commentsedit

https://www.cnblogs.com/dolphin0520/p/3932934.html

学完本章后需要掌握线程间通信,有以下几个知识点

  • wait / notify 实现线程通信
  • 生产者 / 消费者模式的实现
  • 方法join的使用
  • ThreadLocal类的使用

1、wait / notify

Object类的方法,执行这两个方法必须先获得锁,也就是必须在synchronized的代码块或者sync方法中。否则会抛出IllegalMonitorSateException异常。

1.1 wait()

执行wait后马上放弃锁,把线程加入阻塞队列

wait(long) 规定等待的时间,超过时间未被唤醒就自动唤醒。

1.2 notify

执行notify后不放弃锁,把阻塞队列的线程加入就绪队列。

obj1.notifyAll() 唤醒所有obj1.wait()的阻塞队列。

2、生产者消费者问题

多个生产者 多个消费者 针对多个容器进行生产消费操作。
对容器对象进行加锁。

import javax.security.auth.Subject;
import java.util.*;

class Mystack{
    private List<String> list = new ArrayList();

    synchronized public void push() {
        try{
            if (list.size() == 5) {
                System.out.println("空瓶子都放满了,因此wait");
                this.wait();
            }
            list.add("value");
            // 这里如果是notify,那么几率唤醒的是 push线程, 那么push线程
            //任然是阻塞,那么就造成了“假死”
            this.notifyAll();
            System.out.println("push=" + list.size());
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    synchronized public void pop() {
        try{
            if (list.size() == 0) {
                System.out.println("pop 操作 瓶子为空,因此线程等待");
                this.wait();
            }
            System.out.println("pop =" + list.size());
            list.remove(list.size()-1);
            this.notifyAll();

        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ServerPush{
    private Mystack mystack;

    ServerPush(Mystack mystack) {
        this.mystack = mystack;
    }

    public void pushService() {
        mystack.push();
    }
}
class ServerPop{
    private Mystack mystack;

    ServerPop(Mystack mystack) {
        this.mystack = mystack;
    }

    public void popService() {
        mystack.pop();
    }
}

class ThreadPush extends Thread {
    private ServerPush serverPush;

    ThreadPush(ServerPush serverPush) {
        this.serverPush = serverPush;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            serverPush.pushService();
        }

    }
}

class ThreadPop extends Thread {
    private ServerPop serverPop;

    ThreadPop(ServerPop serverPop) {
        this.serverPop = serverPop;
    }
    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            serverPop.popService();
        }

    }
}
public class Main {

    // 一个生产者 一个消费者 , 瓶子数量有多个
    public static void main(String[] args) {
        Mystack mystack = new Mystack();

        ServerPush serverPush = new ServerPush(mystack);
        ThreadPush threadPush = new ThreadPush(serverPush);
        threadPush.start();

        ServerPush serverPush2 = new ServerPush(mystack);
        ThreadPush threadPush2 = new ThreadPush(serverPush2);
        threadPush2.start();

        ServerPush serverPush3 = new ServerPush(mystack);
        ThreadPush threadPush3 = new ThreadPush(serverPush3);
        threadPush3.start();



        ServerPop serverPop = new ServerPop(mystack);
        ThreadPop threadPop = new ThreadPop(serverPop);
        threadPop.start();

        ServerPop serverPop2 = new ServerPop(mystack);
        ThreadPop threadPop2 = new ThreadPop(serverPop2);
        threadPop2.start();

        ServerPop serverPop3 = new ServerPop(mystack);
        ThreadPop threadPop3 = new ThreadPop(serverPop3);
        threadPop3.start();
    }

}

3、thread1.join()

join的作用是:在所属线程结束之前,当前线程无限期阻塞。
join内部使用wait()

3.1 join()的使用
class MyThread extends Thread{
private Thread threadb;

MyThread (Thread threadb){
	this.threadb = threadb;
}
//略写
run(){
 threadb.start();
 threadb.join();
}

3.2 join(long) 和 sleep(long)

join(long)内部调用了wait(long),因此会释放锁

sleep(long)就不会释放锁。

3.3 ThreadLocal

线程可以对ThreadLocal类对象t1进行 t1.set(“obj”) ; t1.get(“obj”) 。等价于每个线程独立拥有一个区域。

继承ThreadLocal ,重写它的initalValue()方法,可以使第一次get到是自定义的初始值

3.4 InheritableThreadLocal

它继承了ThreadLocal,这样子进程可以得到父进程在ThreadLocal中set的值。

另外通过重写InheritableThreadLocal的childValue(),可以在得到父类的set的值之外,添加修改。

子线程可以修改父线程在容器中的值

如果子线程get出容器中的对象,再进行修改,那么父线程可以得到修改后的对象。
如果子线程直接set新的容器对象,那么父线程得到的还是原来的对象。

package nowcoder;

import org.junit.Test;

import javax.swing.tree.TreeNode;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class Main {
    public static ThreadLocal<User> mutableInheritableThreadLocal = new InheritableThreadLocal<User>();
    public static void main(String args[]) throws InterruptedException {
        // 测试2.父线程和子线程的传递关系测试: 可变对象, 父线程初始化;
        // 结论2: 父线程初始化, Thread Construct浅拷贝, 共用索引, 子线程先get()对象, 再修改对象的属性,
        // 父线程跟着变, 注意: 此处子线程如果没有先get()直接使用set()一个新对象, 父线程是不会跟着变的
        mutableInheritableThreadLocal.set(new User("joon"));// 2.1父线程初始化

        Thread TestThread = new TestThread(); // 2.2先初始化父线程再创建子线程, 确保子线程能继承到父线程的User
        TestThread.start(); // 开始执行子进程

        TimeUnit.MILLISECONDS.sleep(100); // 睡眠, 以等待子线程执行完毕
        System.out.println("main = " + mutableInheritableThreadLocal.get()); // 2.5此处输出值为子线程修改的值, 因此可得出上述结论2
        System.out.println();
    }

    private static class TestThread extends Thread {
        @Override
        public void run() {
            // 2.3此处输出父线程的初始化对象值, 代表子线程确实继承了父线程的对象值
            System.out.println("TestThread.before = " + mutableInheritableThreadLocal.get());
            // 2.4子类拿到对象并修改
            mutableInheritableThreadLocal.get().setName("whee");
            mutableInheritableThreadLocal.set(new User("new User"));
            System.out.println("mutableInheritableThreadLocal = " + mutableInheritableThreadLocal.get());
        }
    }
    private static class TestThread2 extends Thread {
        @Override
        public void run() {
             // 直接set 那么父线程不会被改变
            mutableInheritableThreadLocal.set(new User("new User"));
            System.out.println("mutableInheritableThreadLocal = " + mutableInheritableThreadLocal.get());
        }
    }
    private static class User {
        String name;

        public User(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User [name=" + name + "]";
        }

    }

}

可以借助map实现更加广泛的通信

private static final ThreadLocal<Map<Object, Object>> testThreadLocal = new InheritableThreadLocal<Map<Object, Object>>();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值