标签:private 就会 条件 xtend this 默认值 add 监视器 cut
方法名 | 作用 |
---|---|
wait() | 执行当前代码的线程等待 |
wait(long timeout) | timeout时间内若没有其他线程唤醒,也会醒过来 |
wait(long timeout, int nanos) | 超出timeout和额外的时间nanos,没有被其他线程唤醒,也会醒过来 |
方法名 | 作用 |
---|---|
notify() | 随机唤醒一条在等待队列中想去访问同一共享变量的线程 |
void notifyAll() | 唤醒在此对象监视器上等待的所有线程 |
wait()可以使当前线程停下来,等待某个条件发生变化,并且这个条件超出了当前方法的控制范围,可以实现和自旋一样的效果,但是呢,自旋确实一种CPU的不良的使用行为
实例代码:
public class demo1 {
private static List list = new ArrayList();
public void add(){
list.add("string");
}
public int size(){
return list.size();
}
}
public class demo11 {
public static void main(String[] args) {
demo1 demo1 = new demo1();
Object o = new Object();
new Thread(()->{
synchronized (o){
if(demo1.size()!=5){
try {
System.out.println("开始等待..."+ System.currentTimeMillis());
o.wait();
System.out.println("等待结束.."+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(()->{
synchronized (o){
for(int i=0;i<10;i++){
demo1.add();
if (demo1.size()==5){
System.out.println("发出notofy通知...");
o.notify();
}
System.out.println("已经添加了"+i+"个元素");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
运行结果:
开始等待...1549259002081
已经添加了0个元素
已经添加了1个元素
已经添加了2个元素
已经添加了3个元素
发出notofy通知...
已经添加了4个元素
已经添加了5个元素
已经添加了6个元素
已经添加了7个元素
已经添加了8个元素
已经添加了9个元素
等待结束..1549259005086
wait()总结:
notify()总结:
notifyAll()的调用,必须提前获取到锁,而wait()一经调用,立即释放锁,两者不会冲突
public class demo2 {
String lock = new String("");
boolean tag = false;
private Runnable runnableA = new Runnable(){
@Override
public void run() {
synchronized (lock){
try {
while(tag==false) {
System.out.println("runnableA bagin wait...");
lock.wait();
System.out.println("RunnableA wait end...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
private Runnable runnableB = new Runnable(){
@Override
public void run() {
synchronized (lock){
System.out.println("runnableB bagin notify...");
lock.notify();
tag=true;
System.out.println("RunnableB notify end...");
System.out.println("不满足条件不唤醒...");
}
}
};
public static void main(String[] args) {
demo2 demo2 = new demo2();
new Thread(demo2.runnableB).start();
new Thread(demo2.runnableA).start();
}
}
执行结果:
runnableB bagin notify...
RunnableB notify end...
不满足条件不唤醒...
添加了一个判断的条件,实现,若现进行了唤醒,那么不执行wait()
更换两个线程的启动顺序
运行结果:
E:\JavaJDK\bin\java.exe
runnableA bagin wait...
runnableB bagin notify...
RunnableB notify end...
不满足条件不唤醒...
RunnableA wait end...
运行下面的代码:
public class demo33 {
private String lock;
public demo33(String lock){
this.lock =lock;
}
private List list = new ArrayList();
public void add(){
synchronized (lock){
list.add("hello");
System.out.println(Thread.currentThread().getName()+"add hello 然后唤醒所有wait()线程");
//唤醒所有
lock.notifyAll();
}
}
public void subtract(){
synchronized (lock){
if(list.size()==0){
try {
System.out.println(Thread.currentThread().getName()+"开始等待");
lock.wait();
System.out.println(Thread.currentThread().getName() +"等待结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.remove(0);
}
}
}
public static void main(String[] args) {
demo33 demo33 = new demo33("123");
// 第一条等待的线程
new Thread(()->{
demo33.subtract();
}).start();
//第二条等待的线程
new Thread(()->{
demo33.subtract();
}).start();
//唤醒所有
new Thread(()->{
demo33.add();
}).start();
}
运行结果:
Thread-0开始等待
Thread-1开始等待
Thread-2add hello 然后唤醒所有wait()线程
Thread-1等待结束
Thread-0等待结束
Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:657)
/*
* 多生产,多消费的假死现象
* */
public class demo4 {
private List list = new ArrayList();
public void p(Object o){
synchronized (o){
while(!(list.size()==0)){ //对于生产者,list不为空,等待
System.out.println("生产者"+Thread.currentThread().getName()+"等待了...");
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 为空,生产
System.out.println("生产者"+Thread.currentThread().getName()+"生产了...");
list.add("123");
o.notify();
}
}
public void c(Object o){
synchronized (o){
while(list.size()==0){ //对于消费者,size==0 等待
System.out.println("消费者"+Thread.currentThread().getName()+"等待了");
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费者"+Thread.currentThread().getName()+"消费了");
list.remove(0);
o.notify();
}
}
public static void main(String[] args) {
demo4 demo4 = new demo4();
Object o = new Object();
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0;i<5;i++){
executorService.execute(new Runnable() {
@Override
public void run() {
while (true)
demo4.p(o);
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
while (true)
demo4.c(o);
}
});
}
Thread[] threads = new Thread[2];
try {
Thread.sleep(5000);
System.out.println("主函数醒了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行上面的代码结果
.
.
.
生产者pool-1-thread-7等待了...
消费者pool-1-thread-10消费了
消费者pool-1-thread-10等待了
消费者pool-1-thread-8等待了
消费者pool-1-thread-6等待了
主函数醒了
卡顿在最后"主函数醒了"不再往下运行,产生了假死的现象实际上还有线程依然存活,只不过是它一直等待,没人唤醒它,notify()会随机唤醒一条线程,这也就意味着,可能存在生产者唤醒的是生产者,消费者唤醒了消费者,导致双方全部等待而造成假死
很多情况下,主线程中启动子线程,然后两条线程并行运行,主线程往往早于子线程之前结束,那么,假如说主线程想等子线程执行完毕后,拿到子线程的结果后再结束,那么最直接的方法就是 使用join()
public class myjoin extends Thread{
public void run(){
System.out.println("我是子线程,我要睡两秒...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
myjoin myjoin = new myjoin();
myjoin.start();
myjoin.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"我成功的等待子线程执行完后,执行");
}
运行结果
我是子线程,我要睡两秒...
main我成功的等待子线程执行完后,执行
观看如下代码
public class ThreadA extends Thread {
public void run(){
try {
System.out.println("ThreadA 执行了,紧接着睡五秒...");
Thread.sleep(5000);
System.out.println("五秒了, ThreadA 醒过来...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadB extends Thread{
public void run(){
try{
System.out.println("ThreadB 启动了...");
ThreadA threadA = new ThreadA();
threadA.start();
threadA.join();
System.out.println("ThreadA join 之后的代码...");
}catch (Exception e){
System.out.println("ThreadB catch块打印了...");
e.printStackTrace();
}
}
}
public class ThreadC extends Thread {
Thread thread;
public ThreadC(Thread b){
this.thread=b;
}
public void run(){
thread.interrupt();
}
public static void main(String[] args) {
ThreadB threadB = new ThreadB();
threadB.start();
ThreadC threadC = new ThreadC(threadB);
threadC.start();
System.out.println("主线程结束...");
}
}
运行结果:
ThreadB 启动了...
主线程结束...
java.lang.InterruptedException
ThreadB 启动了...
ThreadB catch块打印了...
ThreadA 执行了,紧接着睡五秒...
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1252)
at java.lang.Thread.join(Thread.java:1326)
at com.atGongDa.MultiThreading.线程之间的通信.ThreadB.run(ThreadB.java:10)
五秒了, ThreadA 醒过来...
当时对join()阻塞的是哪条线程的代码还是有点模糊,现在分析结果,可以看到,join阻塞的是join()方法 所在的那条线程,根据上面的例子,join只能阻塞ThreadB,却不能阻塞ThreadC 和 主线程
运行下面的代码:
public class ThreadQ extends Thread{
private Thread W;
public ThreadQ(Thread thread) {
this.W = thread;
}
public void run(){
synchronized (W){
System.out.println("ThreadQ准备开始睡三秒..."+System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadQ...睡醒了..."+System.currentTimeMillis());
}
}
}
public class ThreadW extends Thread {
synchronized public void run() {
try {
System.out.println("ThreadW 启动了...要睡三秒"+System.currentTimeMillis());
Thread.sleep(3000);
System.out.println("ThreadW睡醒了..."+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadE {
public static void main(String[] args) {
ThreadW w = new ThreadW();
ThreadQ threadQ = new ThreadQ(w);
w.start();
threadQ.start();
try {
threadQ.join(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main end...");
}
}
运行结果: 可以看到,main end提前打印出来了
ThreadW 启动了...要睡三秒1549362922247
main end...
ThreadW睡醒了...1549362925248
ThreadQ准备开始睡三秒...1549362925248
ThreadQ...睡醒了...1549362928248
当我们把join(2000)注释掉后结果如下
main end...1549363120715
ThreadQ准备开始睡三秒...1549363120715
ThreadQ...睡醒了...1549363123715
ThreadW 启动了...要睡三秒1549363123715
ThreadW睡醒了...1549363126716
分析结果,不难看出,在线程的启动一条新的线程比它运行自己的代码要快的多.因此,大多数情况下,都是join()方法先执行,拿到对象锁,然后马上释放掉...,然后Q抢到ThreadW对象锁,睡上三秒且不释放,ThreadW因为没有锁,故执行不了自己加上了synchronize的run()方法,本来join()可以阻塞Zhu后面的代码,可是join(2000),发现自己已经过期了,因此ThreadW和ThreadMain就会异步执行
释放掉调用join方法的线程2对象的 对象锁
这也就意味着,其他的线程可以访问调用join方法的线程2的同步方法...
变量值的共享可以使用public static 修饰,所有的线程都使用同一个public static 的变量,如果想实现每一个线程都有自己的共享变量呢? ThreadLocal ,可以把它当成一个专属于当前线程对象的盒子,它保证了线程之前的隔离性
重写 initialValue值设置默认值
@Override
protected Object initialValue() {
return "123";
}
重写childValue方法,实现继承值的修改,
@Override
protected Object childValue() {
return "XXX";
}
注意:
当子线程从父线程中获取值的同时,父线程把值修改了,子线程获取到的值为旧值
参考书籍<
标签:private 就会 条件 xtend this 默认值 add 监视器 cut
原文地址:https://www.cnblogs.com/ZhuChangwu/p/11150310.html