https://blog.csdn.net/a724888/article/details/60867081#commentsedit
https://www.cnblogs.com/dolphin0520/p/3932934.html
学完本章后需要掌握线程间通信,有以下几个知识点
Object类的方法,执行这两个方法必须先获得锁,也就是必须在synchronized的代码块或者sync方法中。否则会抛出IllegalMonitorSateException异常。
执行wait后马上放弃锁,把线程加入阻塞队列
wait(long) 规定等待的时间,超过时间未被唤醒就自动唤醒。
执行notify后不放弃锁,把阻塞队列的线程加入就绪队列。
obj1.notifyAll() 唤醒所有obj1.wait()的阻塞队列。
多个生产者 多个消费者 针对多个容器进行生产消费操作。
对容器对象进行加锁。
import javax.security.auth.Subject;
import java.util.*;
class Mystack{
private List 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();
}
}
join的作用是:在所属线程结束之前,当前线程无限期阻塞。
join内部使用wait()
class MyThread extends Thread{
private Thread threadb;
MyThread (Thread threadb){
this.threadb = threadb;
}
//略写
run(){
threadb.start();
threadb.join();
}
join(long)内部调用了wait(long),因此会释放锁
sleep(long)就不会释放锁。
线程可以对ThreadLocal类对象t1进行 t1.set(“obj”) ; t1.get(“obj”) 。等价于每个线程独立拥有一个区域。
继承ThreadLocal ,重写它的initalValue()方法,可以使第一次get到是自定义的初始值
它继承了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 mutableInheritableThreadLocal = new InheritableThreadLocal();
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