栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java线程间通信

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java线程间通信

Java关键字synchronized的使用
该篇文章主要内容有:

  1. 使用wait、notify实现线程间的通信
  2. 生产者/消费者模式的实现
  3. 方法join的使用
  4. ThreadLocal类的使用
1.1:等待/通知机制的实现

  线程与线程之间不是独立的个体,它们彼此可以互相通信和协作。

  方法wait()的作用是使当前执行代码的线程进行等待,在调用该方法之前, 线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用,不然将会抛出异常IllegalMonitorStateException。

  方法notify()也要在同步方法或同步块中调用,调用该方法时,如果有多个线程等待该对象锁,则由线程规划器随机挑选一个呈wait状态的线程,对其发出notify通知。需要注意的是:在执行notify方法后,当前线程并不会马上释放对象锁,wait状态的线程也不会马上获得锁,要等到执行notify线程将程序执行完,即退出同步代码后才释放锁。如果没有调用notify,即使该线程释放了锁,wait状态的线程也无法再次获得锁
注:

  1. wait()释放锁,notify不释放锁。
  2. wait()方法与sleep()方法区别也是sleep不会释放锁
  3. wait(long)表示等待该时间内是否有线程对其进行唤醒,否则超过这个时间自动唤醒。



1.2: wait方法与notify方法细节 1.2.1: 当interrupt方法遇到wait方法

当线程处于wait()状态时,调用该对象的interrupt方法会出现异常。

1.2.2:同时唤醒多个线程

1、使用多次notify()



2、使用notifyAll()一次唤醒全部


1. notify方法的执行不应该在wait()方法之前执行,不然会打乱正常的运行顺序。
2. 还需要注意的是,wait等待的条件发生了变化,也会打乱正常的运行顺序。

出现错误的原因是

notifyAll唤醒了两个等待的进程,而list只有一个数据可供删除,所以出现了索引错误。解决办法就是将if判断设置为while循环判断。

1.3: 生产者/消费者模式的实现 1.3.1: 一生产者与一消费者:操作值




从结果可以看出来此时两个线程是交替执行的,但是如果是多线程(多生产者与消费者)的话,则可能出现假死现象,因为你使用notify唤醒的线程一旦是同类,例如:生产者唤醒了生产者,此时所有线程都无法继续运行下去了。这个问题的解决办法就是使用notidyAll唤醒所有的线程,但效率不高。

1.3.2: 多生产者与多消费者:操作栈

MyStack.java

package com.zjw;
import java.util.ArrayList;
public class MyStack {
    private String lock;
    private ArrayListlist;
    private int i=0;
    public MyStack(String lock){
        this.lock=lock;
        list=new ArrayList<>();
    }
    public void p(){
        try {
            Thread.sleep(100);//设置睡眠时间防止同一线程一直争抢到锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (lock) {
            while (list.size()>50) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.add(i);
            System.out.println("我是生产者"+Thread.currentThread().getName()+"我生产了数据"+i);
            i++;
            lock.notifyAll();
        }
    }
    public void c(){
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (lock) {
            while (list.size()==0) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            int j=list.remove(0);
            System.out.println("我是消费者"+Thread.currentThread().getName()+"我去除了数据"+j);
            lock.notifyAll();
        }
    }
}



1.3.3: join方法

方法join()的作用是主线程(在线程内使用该方法)等待子线程执行完成之后再结束。

如果在main方法不使用join的话,则无法判断何时才执行后面的代码,join有点类似与同步的运行效果,在内部使用wait()方法进行等待,而synchronized关键字使用的是“对象监视器”。
join(long)方法是设定等待的时间,那么它与sleep(long)的方法的区别呢?那就是它内部使用的是wait(long),它在等待的时候会释放锁。
注:因为join()与释放锁这个操作,所以可能释放之后其他线程争抢锁有不同的情况,导致程序结果也有不同的结果。

1.4 类ThreadLocal的使用

类ThreadLocal可以实现每一个线程都有自己的共享变量,解决变量在不同线程之间的隔离性,使每个线程拥有自己的值。



注:第一次调用get()方法(如果之前没有使用set方法的话)返回的是NULL,如果想让它第一次不返回NULL,则可以自己继承ThreadLocal然后重写 initialValue方法。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/284723.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号