精华内容
下载资源
问答
  • 线程通信

    2018-03-27 22:32:33
    线程通信 不同的线程执行不同的任务,如果这些任务之间有某种联系,线程之间必须能够通信,协调完成工作。 java.lang,Object类中提供了两种用于线程通信的方法: wait():执行该方法的线程释放对象的锁,虚拟机...

    线程通信

    不同的线程执行不同的任务,如果这些任务之间有某种联系,线程之间必须能够通信,协调完成工作。

    java.lang,Object类中提供了两种用于线程通信的方法:

    1. wait():执行该方法的线程释放对象的锁,虚拟机把该线程放到对象的等待池中,等待其他线程将它唤醒。
    2. notice():执行该方法的线程唤醒在对象等待池中等待的一个线程。如果对象的等待池中不止一个线程在等待,虚拟机会随机选择一个线程唤醒,把它转化到对象的锁池中。
    3. noticeAll():该方法会把对象等待池中所有线程都转到对象的锁池中等待。

    中断阻塞

    当线程A处于阻塞状态时,如果线程B调用线程A的interrupt()方法,那么线程A就会接受到一个InterruptedException异常,线程A退出阻塞状态,开始处理异常。

    展开全文
  • Java多线程07_线程通信之管程法与信号灯法 线程通信 的应用场景是 消费者/生产者问题: 解决线程通信的方法: wait() 表示线程一直等待,直到接到通知(会释放锁) wait(long timeout) 指定线程等待的毫秒数 ...

    Java多线程07_线程通信之管程法与信号灯法


    线程通信 的应用场景是 消费者/生产者问题:

    解决线程通信的方法:

    wait()				表示线程一直等待,直到接到通知(会释放锁)
    wait(long timeout)	指定线程等待的毫秒数
    notify()			唤醒一个处于等待状态的线程
    notifyAll()			唤醒同一个对象上的所有处于等待状态的线程
    

    管程法(通过缓冲区):

    生产者生产商品并存入缓冲区,消费者从缓冲区中消费商品。
    消费者消费产品后通知生产者生产,当缓冲区产品不足时,消费者线程等待
    生产者生产产品后通知消费者消费,如果缓冲区已满,生产者线程等待

    在这里插入图片描述

    public class TestPC {
    	
    	public static void main(String[] args) {
    		
    		SynContainer container = new SynContainer();
    		new Producer(container).start();
    		new Customer(container).start();
    	}
    
    }
    
    class Producer extends Thread{
    	
    	SynContainer container;
    	
    	public Producer(SynContainer container) {
    		this.container = container;
    	}
    	
    	@Override
    	public void run() {
    		for(int i=0;i<100;i++) {
    			System.out.println("生产了第"+i+"只鸡");
    			container.push(new Chicken(i));
    		}
    	}
    	
    }
    
    class Customer extends Thread{
    	
    	SynContainer container;
    	
    	public Customer(SynContainer container) {
    		this.container = container;
    	}
    	
    	@Override
    	public void run() {
    		for(int i=0;i<100;i++) {
    			System.out.println("消费了第"+container.pop().id+"只鸡");
    			
    		}
    	}
    }
    
    class Chicken{
    	int id;
    
    	public Chicken(int id) {
    		super();
    		this.id = id;
    	}
    
    }
    
    //缓冲区
    class SynContainer{
    	
    	Chicken[] chickens = new Chicken[10];
    	
    	int count = 0;
    	
    	public synchronized void push(Chicken chicken) {
    		
    		//如果缓冲区已满则生产者等待
    		if(count==chickens.length) {
    			try {
    				this.wait();
    			}catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		//缓冲区未满则生产,并通知消费者消费
    		chickens[count]=chicken;
    		count++;
    		this.notifyAll();
    	}
    	
    	public synchronized Chicken pop() {
    		
    		//如果缓冲区为空则消费者等待
    		if(count==0) {
    			try {
    				this.wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		//缓冲区不为空则消费,并通知生产者生产
    		count--;
    		Chicken chicken = chickens[count];
    		this.notifyAll();
    		return chicken;
    	}
    }
    
    生产了第0只鸡
    生产了第1只鸡
    消费了第0只鸡
    生产了第2只鸡
    消费了第1只鸡
    生产了第3只鸡
    消费了第2只鸡
    生产了第4只鸡
    消费了第3只鸡
    消费了第4只鸡
    生产了第5只鸡
    生产了第6只鸡
    消费了第5只鸡
    生产了第7只鸡
    消费了第6只鸡
    生产了第8只鸡
    消费了第7只鸡
    生产了第9只鸡
    消费了第8只鸡
    生产了第10只鸡
    消费了第9只鸡
    生产了第11只鸡
    消费了第10只鸡
    生产了第12只鸡
    消费了第11只鸡
    生产了第13只鸡
    消费了第12只鸡
    生产了第14只鸡
    消费了第13只鸡
    生产了第15只鸡
    生产了第16只鸡
    消费了第14只鸡
    消费了第16只鸡
    生产了第17只鸡
    消费了第15只鸡
    生产了第18只鸡
    消费了第17只鸡
    生产了第19只鸡
    消费了第18只鸡
    生产了第20只鸡
    消费了第19只鸡
    生产了第21只鸡
    消费了第20只鸡
    生产了第22只鸡
    消费了第21只鸡
    生产了第23只鸡
    消费了第22只鸡
    生产了第24只鸡
    消费了第23只鸡
    生产了第25只鸡
    消费了第24只鸡
    生产了第26只鸡
    消费了第25只鸡
    生产了第27只鸡
    消费了第26只鸡
    生产了第28只鸡
    消费了第27只鸡
    生产了第29只鸡
    消费了第28只鸡
    生产了第30只鸡
    消费了第29只鸡
    生产了第31只鸡
    消费了第30只鸡
    生产了第32只鸡
    消费了第31只鸡
    生产了第33只鸡
    消费了第32只鸡
    生产了第34只鸡
    消费了第33只鸡
    生产了第35只鸡
    消费了第34只鸡
    生产了第36只鸡
    消费了第35只鸡
    生产了第37只鸡
    消费了第36只鸡
    生产了第38只鸡
    消费了第37只鸡
    生产了第39只鸡
    消费了第38只鸡
    生产了第40只鸡
    消费了第39只鸡
    生产了第41只鸡
    消费了第40只鸡
    生产了第42只鸡
    消费了第41只鸡
    生产了第43只鸡
    消费了第42只鸡
    生产了第44只鸡
    消费了第43只鸡
    生产了第45只鸡
    消费了第44只鸡
    生产了第46只鸡
    消费了第45只鸡
    生产了第47只鸡
    消费了第46只鸡
    生产了第48只鸡
    消费了第47只鸡
    生产了第49只鸡
    生产了第50只鸡
    消费了第48只鸡
    生产了第51只鸡
    消费了第50只鸡
    生产了第52只鸡
    消费了第51只鸡
    生产了第53只鸡
    消费了第52只鸡
    生产了第54只鸡
    消费了第53只鸡
    生产了第55只鸡
    消费了第54只鸡
    生产了第56只鸡
    消费了第55只鸡
    生产了第57只鸡
    消费了第56只鸡
    生产了第58只鸡
    消费了第57只鸡
    消费了第58只鸡
    生产了第59只鸡
    消费了第49只鸡
    生产了第60只鸡
    消费了第59只鸡
    生产了第61只鸡
    消费了第60只鸡
    生产了第62只鸡
    消费了第61只鸡
    生产了第63只鸡
    消费了第62只鸡
    生产了第64只鸡
    消费了第63只鸡
    生产了第65只鸡
    消费了第64只鸡
    生产了第66只鸡
    消费了第65只鸡
    生产了第67只鸡
    消费了第66只鸡
    生产了第68只鸡
    消费了第67只鸡
    生产了第69只鸡
    消费了第68只鸡
    生产了第70只鸡
    消费了第69只鸡
    生产了第71只鸡
    消费了第70只鸡
    生产了第72只鸡
    消费了第71只鸡
    生产了第73只鸡
    消费了第72只鸡
    生产了第74只鸡
    消费了第73只鸡
    生产了第75只鸡
    消费了第74只鸡
    生产了第76只鸡
    消费了第75只鸡
    生产了第77只鸡
    消费了第76只鸡
    生产了第78只鸡
    消费了第77只鸡
    生产了第79只鸡
    消费了第78只鸡
    生产了第80只鸡
    生产了第81只鸡
    消费了第79只鸡
    生产了第82只鸡
    消费了第81只鸡
    生产了第83只鸡
    消费了第82只鸡
    生产了第84只鸡
    消费了第83只鸡
    生产了第85只鸡
    消费了第84只鸡
    生产了第86只鸡
    消费了第85只鸡
    生产了第87只鸡
    消费了第86只鸡
    生产了第88只鸡
    消费了第87只鸡
    生产了第89只鸡
    消费了第88只鸡
    生产了第90只鸡
    消费了第89只鸡
    生产了第91只鸡
    消费了第90只鸡
    生产了第92只鸡
    消费了第91只鸡
    生产了第93只鸡
    消费了第92只鸡
    生产了第94只鸡
    消费了第93只鸡
    生产了第95只鸡
    消费了第94只鸡
    生产了第96只鸡
    消费了第95只鸡
    生产了第97只鸡
    消费了第96只鸡
    生产了第98只鸡
    消费了第97只鸡
    生产了第99只鸡
    消费了第98只鸡
    消费了第99只鸡
    消费了第80只鸡
    

    信号灯法(通过标志位):

    标志位为 true,表示产品为空
    当标志位为 true,生产者生产产品,并将标志位设为false,通知消费者消费
    当标志位为 false,消费者消费产品,并将标志位设为true,通知生产者生产

    public class TestPC2 {
    	
    	public static void main(String[] args) {
    		TV tv = new TV();
    		new Actor(tv).start();
    		new Audience(tv).start();
    		
    	}
    
    }
    
    class Actor extends Thread{
    	
    	TV tv;
    	
    	public Actor(TV tv) {
    		this.tv = tv;
    	}
    	
    	@Override
    	public void run() {
    		for(int i=0;i<20;i++) {
    			if(i%2==0) {
    				this.tv.perform("节目");
    			}else {
    				this.tv.perform("广告");
    			}
    		}
    	}
    	
    }
    
    class Audience extends Thread{
    	
    	TV tv;
    	
    	public Audience(TV tv) {
    		this.tv = tv;
    	}
    	
    	@Override
    	public void run() {
    		for(int i=0;i<20;i++) {
    			tv.watch();
    		}
    	}
    	
    }
    
    class TV{
    	
    	String show;
    	boolean flag = true;
    	
    	public synchronized void perform(String show) {
    		
    		if(!flag) {
    			try {
    				this.wait();
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    		
    		System.out.println("演员表演了:"+show);
    		this.show=show;
    		this.notifyAll();
    		this.flag = !this.flag;
    	}
    	
    	public synchronized void watch() {
    		if(flag) {
    			try {
    				this.wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println("观众观看了:"+show);
    		this.notifyAll();
    		this.flag = !flag;
    		
    	}
    	
    }
    
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    演员表演了:节目
    观众观看了:节目
    演员表演了:广告
    观众观看了:广告
    
    展开全文
  • Java线程: 线程通信

    千次阅读 2018-08-18 10:35:24
    本文主要是讲解Java线程中线程通信. (1)传统的线程通信 (2)使用Condition控制线程通信 (3)使用阻塞队列控制线程通信

    当线程在系统内运行时,线程的调度具有一定的透明性,程序通常无法准确控制线程的轮换执行,但Java也提供了一些机制来保证线程协调运行。

    一.传统的线程通信

    假设现在系统中有两个线程,这两个线程分别代表存款者和取钱者,现在假设系统有一个特殊的要求,系统要求存款者和取钱者不断地重复存款、取钱的动作,并且要求每当存款者将钱存入指定账户后,取钱者就立即取出该笔钱。不允许存款者连续两次存钱,也不允许取钱者联系两次取钱。

    为了实现这个功能,可以借助于Object类提供的wait()、notify()和notifyAll() 三个方法,这三个方法并不属于Thread类,而是属于Object类。但这三个方法必须由同步监视器来调用,这可分成以下两种情况。

    (1)对于使用synchronized修饰的同步方法,因为该类的默认实例(this)就是同步监视器,所以可以在同步方法中直接调用这三个方法。

    (2)对于使用synchronized修饰的同步代码块,同步监视器是synchronized后括号里的对象,所以必须使用该对象调用这三个方法。

    关于这三个方法的解释如下:
    (1)wait() : 导致当前线程等待,直到其他线程调用该同步监视器的notify()方法或notifyAll()方法来唤醒该线程。该wait()方法有三种形式——无时间参数的wait(一直等待,直到其他线程通知)、带毫秒参数的wait()和带毫秒、毫微秒的wait() (这两种方法都是等待指定时间后自动苏醒)。调用wait()方法的当前线程会释放对该同步监视器的锁定。

    (2)notify() : 唤醒在此同步监视器上等待的单个线程。如果所有线程都在此同步监视器上等待,则会选择唤醒其中一个线程。选择是任意性的。只有当前线程放弃对该同步监视器的锁定后(使用wait()方法),才可以执行被唤醒的线程。

    (3)notifyAll() : 唤醒在此同步监视器上等待的所有线程。只有当前线程放弃对该同步监视器的锁定后,才可以执行被唤醒的线程。

    程序中可以通过一个flag来标识账户中是否已有存款,当flag为false时,表明账户中没有存款,存款者线程可以向下执行,当存款者把钱存入账户后,将flag设为true,并调用notify()或notifyAll()方法来唤醒其他线程;当存款者线程进入线程体后,如果flag为true就调用wait()方法让线程等待。

    当flag为true时,表明账户中已经存入了存款,则取钱者线程可以向下执行,当取钱者把钱从账户中取出时,将flag设为false,并调用notify()或notifyAll()方法来唤醒其他线程;当取钱者线程进入线程体后,如果flag为false就调用wait()方法让线程等待。

    本程序为Account类提供draw()和deposit()两个方法,分别对应该账户的取钱、存款等操作,因为这两个方法可能需要并发修改Account类的balance成员变量的值,所以这两个方法都使用synchronized修饰成同步方法。除此之外,这两个方法还使用了wait()、notifiyAll()来控制线程的协作。

    Account类

    代码片1
    public class Account {
    
        private String  accountNo;
        private double  balance;
        //标识账户中是否已有存款的flag
        private boolean flag = false;
    
        public Account() {
        }
    
        public Account(String accountNo, double balance) {
            this.accountNo = accountNo;
            this.balance = balance;
        }
    
        public String getAccountNo() {
            return accountNo;
        }
    
        public void setAccountNo(String accountNo) {
            this.accountNo = accountNo;
        }
    
        public double getBalance() {
            return balance;
        }
    
        public synchronized void draw(double drawAmount) {
            try {
                if (!flag) {
                    //如果flag为假,表明账户中还没有人存钱进去,取钱方法阻塞
                    wait();
                } else {
                //执行取钱操作
                    System.out.println(Thread.currentThread().getName() + "取钱:" + drawAmount);
                    balance -= drawAmount;
                    System.out.println("账户余额为:" + balance);
                    flag = false;
                    //唤醒其他线程
                    notifyAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public synchronized void deposit(double depositAmount) {
            try {
                if (flag) {
                 //如果flag为真,表明账户中已有人存钱进去,存钱方法阻塞
                    wait();
                } else {
                  //执行存款操作
                    System.out.println(Thread.currentThread().getName() + "存钱:" + depositAmount);
                    balance += depositAmount;
                    System.out.println("账户余额为:" + balance);
                    flag = true;
                    notifyAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    代码片2
    public class DrawThread extends Thread {
    
        private Account account;
        private double  drawAmount;
    
        public DrawThread(String name, Account account, double drawAmount) {
            super(name);
            this.account = account;
            this.drawAmount = drawAmount;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                account.draw(drawAmount);
            }
        }
    }
    
    代码片3
    public class DepositThread extends Thread {
    
        private Account account;
        private double  drawAmount;
    
        public DepositThread(String name, Account account, double drawAmount) {
            super(name);
            this.account = account;
            this.drawAmount = drawAmount;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                account.deposit(drawAmount);
            }
        }
    }
    
    代码片4
     Account account = new Account("1234567", 0);
     new DrawThread("取钱者", account, 800).start();
     new DepositThread("存钱者甲", account, 800).start();
     new DepositThread("存钱者乙", account, 800).start();
     new DepositThread("存钱者丙", account, 800).start();
    

    运行该程序,可以看到存款者线程、取钱者线程交替执行的情形,每当存款者向账户中存入800元之后,取钱者线程立刻从账户中取出这笔钱.存款完成后账户余额总是800元,取钱结束后账户余额总是0元.运行该程序,会看到如下图的日志:
    在这里插入图片描述
    从上图可以看出,3个存款者线程随机地向账户中存款,只有1个取钱者线程执行操作.只有当取钱者取钱后,存款者才可以存款;同理,只有等存款者存款后,取钱者线程才可以取钱。

    上图显示程序最后被阻塞无法继续向下执行,这是因为3个存款者线程共有300次存款操作,但1个取钱者线程只有100次取钱操作,所以程序最后被阻塞。

    另外,需要说明的是,阻塞并不是死锁.对于上述情况,取钱者线程已经执行结束,而存款者线程只是在等待其他线程来取钱而已,并不是等待其他线程释放同步监视器。

    二.使用Condition控制线程通信

    如果程序不使用synchronized关键词来保证同步,而是直接使用Lock对象来保证同步,则系统中不存在隐式的同步监视器,也就不能使用wait()、notify()、notifyAll()方法进行线程通信了。

    当使用Lock对象来保证同步时,Java提供了一个Condition类来保持协调,使用Condition可以让那些得到Lock对象却无法继续执行的线程释放Lock对象,Condition对象也可以唤醒其他处于等待的线程。

    Condition将同步监视器方法(wait()、notify()、notifyAll())分解成截然不同的对象,以便通过将这些对象与Lock对象组合使用,为每个对象提供多个等待集(wait-set)。在这种情况下,Lock替代了同步方法与同步代码块,Condition替代了同步监视器的功能。

    Condition实例被绑定在了一个Lock对象上.要获取特定Lock实例的Condition实例,调用Lock对象的newCondition()方法即可。Condition类提供了如下三个方法:

    (1)awit() :类似于同步监视器上的wait()方法,导致当前线程等待,直到其他线程调用该Condition的signal()方法或signalAll()方法来唤醒该线程。该await() 方法有更多变体,如long awaitNanos(long nanosTimeout)、void awaitUnintterruptibly()、awaitUntil(Date deadline)等,可以完成更丰富的等待操作。

    (2)signal() :唤醒在此Lock对象上等待的单个线程。如果所有线程都在此Lock对象上等待,则会选择唤醒其中一个线程。选择是任意性的。只有当前线程放弃对该Lock对象的锁定后(使用await()方法),才可以执行被唤醒的线程。

    (3)signalAll() :唤醒在此Lock对象上等待的所有线程。只有当前线程放弃对该Lock对象的锁定后,才可以执行被唤醒的线程。

    下面代码中Account2使用Lock对象来控制同步,并使用Condition对象来控制线程的协调运行。

    代码片5
    package com.glh.threaddemo;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class Account2 {
    
        //显示定义Lock对象
        private final Lock      lock = new ReentrantLock();
        //获取指定Lock对象的Condition
        private final Condition cond = lock.newCondition();
    
        private String  accountNo;
        private double  balance;
        private boolean flag = false;
    
        public Account2() {
        }
    
        public Account2(String accountNo, double balance) {
            this.accountNo = accountNo;
            this.balance = balance;
        }
    
        public String getAccountNo() {
            return accountNo;
        }
    
        public void setAccountNo(String accountNo) {
            this.accountNo = accountNo;
        }
    
        public double getBalance() {
            return balance;
        }
    
        public void draw(double drawAmount) {
    
            //加锁
            lock.lock();
    
            try {
                if (!flag) {
                    //如果flag为假,表明账户中还没有存钱进入,取钱方法阻塞
                    cond.await();
                } else {
                    System.out.println(Thread.currentThread().getName() + "取钱:" + drawAmount);
                    balance -= drawAmount;
                    System.out.println("账户余额为:" + balance);
                    flag = false;
                    //唤醒其他线程
                    cond.signalAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //使用finally释放锁
                lock.unlock();
            }
        }
    
        public void deposit(double depositAmount) {
            lock.lock();
            try {
                if (flag) {
                    //如果flag为真,表明账户中已有人存钱进入,存钱方法阻塞
                    cond.await();
                } else {
                    //执行存款操作
                    System.out.println(Thread.currentThread().getName() + "存钱:" + depositAmount);
                    balance += depositAmount;
                    System.out.println("账户余额为:" + balance);
                    flag = true;
                    //唤醒其他线程
                    cond.signalAll();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    
    

    而DrawThread类、DepositThread类与代码片2、3一样。

    对比代码片1和代码片5,不难发现这两个程序的逻辑基本相似,只有现在显示地使用Lock对象来充当同步监视器,则需要使用Condition对象来暂停、唤醒指定线程。

    最后运行的结果,也完全一样。

    三.使用阻塞队列(BlockingQueue)控制线程通信

    Java5提供了一个BlockingQueue接口,虽然BlockingQueue也是Queue的子接口,但它的主要用途并不是作为容器,而是作为线程同步的工具。BlockingQueue具有一个特征:当生产者线程视图向BlockingQueue中放入元素时,如果该队列已满,则该线程会被阻塞;当消费者线程视图从BlockingQueue中取出元素时,如果该队列已空,则该线程被阻塞。

    程序的两个线程通过交替向BlockingQueue中放入元素、取出元素,即可很好地控制线程的通信。

    BlockingQueue在实际开发中很少,具体的使用这里不详细展开。

    展开全文
  • 3.6 线程通信

    千次阅读 2021-02-04 00:35:31
    3.6 线程通信        线程通信是指不同线程之间相互传递信息。线程通信可以实现线程等待其他线程执行结果后再执行,这样来实现不同线程之间按照有序的方式进行工作。  &...

    3.6 线程通信

           线程通信是指不同线程之间相互传递信息。线程通信可以实现线程等待其他线程执行结果后再执行,这样来实现不同线程之间按照有序的方式进行工作。
           那么问题来了,Java要如何实现线程间通信呢?
    在这里插入图片描述


    3.6.1 实现通信–共享变量

           可以通过共享变量来实现,实现思路就是一个通过一个共享变量状态的改变来实现线程通信。下边就从代码来看下。
    在这里插入图片描述

    public class SignalDemo {
    //    private Object obj = new Object();
        boolean singal = false;
        public boolean isSingal() {
            return singal;
        }
        public void setSingal(boolean singal) {
            this.singal = singal;
        }
        public static void main(String[] args) {
            SignalDemo signalDemo = new SignalDemo();
            new Thread(()->{
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                signalDemo.setSingal(true);
                System.err.println("\r\n线程2修改信号值");
            }).start();
    
            while (!signalDemo.isSingal()){
                System.err.print("k");
            }
        }
    }
    
    

    在这里插入图片描述
           上例实现的就是一个线程工作,然后另一个线程通过改变共享变量来终止工作线程,Just it!


    3.6.2 wait-notify机制

           官方注释:wait方法可以使当前线程进入等待直到其他线程调用了对象的notify或者notifyAll方法。该方法本质上调用的是wait(0).

     * Causes the current thread to wait until another thread invokes the
     * {@link java.lang.Object#notify()} method or the
     * {@link java.lang.Object#notifyAll()} method for this object.
     * In other words, this method behaves exactly as if it simply
     * performs the call {@code wait(0)}.
    

           现在了解了wait-notify的机制后看一个小demo。用两个线程一个线程输出0-100以内的奇数,一个线程输出0-100以内的偶数。

    class SignalDemo2{
        Object myMonitorObject = new Object();
    
        public void doWait(){
            synchronized(myMonitorObject){
                try{
                    myMonitorObject.wait();
                } catch(InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    
        public void doNotify(){
            synchronized(myMonitorObject){
                myMonitorObject.notify();
            }
        }
    
        public static void main(String[] args) {
            Object o = new Object();
            AtomicInteger i= new AtomicInteger();
            new Thread(()->{
                synchronized (o){
                    while (i.get() <=100){
                        if (i.get() %2==0) {
                            System.err.println(Thread.currentThread() + ":" + i);
                            i.getAndIncrement();
                            try {
                                o.wait();
                                o.notify();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }).start();
    
            new Thread(()->{
                synchronized (o){
                    while (i.get() <=100){
                        if (i.get() %2!=0) {
                            System.err.println(Thread.currentThread() + ":" + i);
                            i.getAndIncrement();
                            try {
                                o.notify();
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }).start();
        }
    }
    

           该实现原理非常简单,当一个线程输出奇数或者偶数后,就使当前线程进入等待状态,并且通知对方操作。 注意:当使用wait-notify机制的时候不要使用String对象或者全局变量的wait方法,可能会由于String常量引用导致意想不到的结果。

    展开全文
  • 多线程之线程通信wait和notify的使用

    千次阅读 2018-06-20 09:26:46
    线程通信
  • Java线程(九):Condition-线程通信更高效的方式

    万次阅读 多人点赞 2012-04-20 14:49:39
    Lock可以更好的解决线程同步问题,使之更面向对象,并且ReadWriteLock在处理同步时更强大,那么同样,线程间仅仅互斥是不够的,还需要通信,本篇的内容是基于上篇之上,使用Lock如何处理线程通信。 那么引入本篇的...
  • Java线程通信

    万次阅读 2019-08-21 23:26:20
    其实把ABC当做线程,这便是一个线程通信的例子。 wait(); 使执行的线程进行等待 notify(); 使停止的线程继续运行, join(); 使所属线程正常执行run方法,而当前线程暂时阻塞,有排队的作用 notify与no...
  • 线程通信机制

    千次阅读 2018-09-24 16:23:47
    一 java实现线程通信机制主要通过以下几种方式 1 while()轮询 2 等待/通知机制 wait()、notify()、notifyAll()结合synchronized关键字 3 条件对象:Condition Condition和ReentrantLock重入锁     此外,...
  • iOS IPC 线程通信

    2018-02-25 13:49:12
    iOS IPC 线程通信 iOS IPC 线程通信 performSelectoronThread NSMachPort GCD 在iOS中 线程通信有两种方式: performSelector:onThread NSMachPort GCD performSelector:onThread //在指定线程调用 ...
  • 线程--简单多线程通信实例

    千次阅读 2017-11-06 15:29:36
    线程通信
  • 17. 线程通信-Condition

    2019-09-01 18:49:20
    1. 线程通信-Condition 当使用synchronized 进行线程同步时, 可以使用Object的wait(), notify(), notifyAll() 方法进行线程通信. 但是当使用Lock 对象保证线程同步时, 便不能使用Object 的方法来进行线程通信了,...
  • 架构系列——线程通信的实现方式

    千次阅读 2020-02-13 20:52:13
    一、什么是线程通信? 二、线程通信的实现 1.使用volatile实现线程通信 2.使用wait/notify实现线程通信 3.使用ReentrantLock创建Condition实现 4.通过LockSupport实现线程通信 5.使用CountDownLatch实现线程...
  • 1.线程安全 当多个线程访问一个类(对象或...线程通信概念:线程是操作系统中的独立个体,但是个体如果不经过特殊处理就不能称为一个整体通信,线程间的通信就成为整体的必用方式之一,当线程存在通信指挥,系统间...
  • 本文参考于线程通信与进程通信的区别 。 进程和线程的区别:对于进程来说,子进程是父进程的复制品,从父进程那里获得父进程的数据空间,堆和栈的复制品。而线程,相对于进程而言,是一个更加接近于执行体的概念,...
  • 操作系统的主要任务是管理计算机的软件、硬件资源。现代操作系统的主要特点是多用户和多任务,也就是程序的并行执行,...而线程通信又和进程间的通信不同。由于进程的数据空间相对独立而线程是共享数据空间的,
  • Python线程通信

    千次阅读 2014-08-13 17:57:05
    Python线程通信 Author:palydawn Date:2012.5.23 Email:palydawn@163.com    最近用python写了一个网络爬虫,很多个线程同时抓取网页。程序里面设定的线程停止条件是下载的网页数大于一个实现确定...
  • 线程通信

    2013-03-18 16:33:41
    线程通信的方法主要有以下三种: 1.全局变量 进程中的线程间内存共享,这是比较常用的通信方式和交互方式。 注:定义全局变量时最好使用volatile来定义,以防编译器对此变量进行优化。 2.Message消息机制 ...
  • 本文参考于线程通信与进程通信的区别 。 进程和线程的区别:对于进程来说,子进程是父进程的复制品,从父进程那里获得父进程的数据空间,堆和栈的复制品。而线程,相对于进程而言,是一个更加接近于执行体的概念,...
  • 1. 线程同步 总结:线程之间进行同步的方法--------用synchronized关键字保证原子性...2. 线程通信 法一:synchronized关键字锁住共同操作对象的方法:(案例生产者,消费者模型) 实体类: 操作对象实体类: 1) Sy
  • 多线程之线程通信

    万次阅读 2018-02-28 15:56:33
    http://blog.csdn.net/jiazhen/article/details/1611721简介 线程之间通信的两个基本问题是互斥和同步。 线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程...
  • Java 线程通信

    2012-04-17 18:49:55
    一位HR朋友最近在招java工程师的时候,遇到了这样一个现象:很多java技术人员都讲自己熟悉多线程,却压根不知线程通信为何物。恰巧的是,该职位对java线程通信要求甚高,朋友因迟迟招不到理想的工程师困惑不已。鉴于...
  • Socket实现多线程通信

    2016-08-21 03:23:17
    我现在想做一个基于Java的Socket多线程通信的demo,服务端可以接受客户端发过来的数据,客户端是硬件,要求只知道服务端的IP及端口就可以发数据,不知道服务端怎么写,求大家的帮助,最好有代码,谢谢
  • 比如大家熟知的消息中间件的实现,从某种角度上讲,就借助了多线程通信的思想,下面总结了JDK中常用的几种实现线程通信的方式,提供参考 1、synchronized实现方式 可能很多小伙伴们会有疑问,synchronized是对共享...
  • Java线程通信的原理详解和案例演示

    千次阅读 2020-03-18 13:02:51
    本文详细介绍了Java线程通信的原理、目的、方法,在文章最后给出了多个线程通信案例。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,853
精华内容 16,741
关键字:

线程通信