java线程间通信
A. java线程间通信的几种方式
Java多线程间的通信
Java还提供了一种线程间通信的机制,这种通信通什么实现?
wait,notify等机制
或使用pipeInputStream和pipeOutputStream
1. 线程的几种状态
线程有四种状态,任何一个线程肯定处于这四种状态中的一种:
1) 产生(New):线程对象已经产生,但尚未被启动,所以无法执行。如通过new产生了一个线程对象后没对它调用start()函数之前。
2) 可执行(Runnable):每个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不一定正在执行中。
3) 死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。
4) 停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。
B. java线程间通信有几种方式
由于线程A和线程B持有同一个MyObject类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的,比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了 通信。
C. 如何在学习Java过程中实现线程之间的通信
在java中,每个对象都有两个池,锁池(monitor)和等待池(waitset),每个对象又都有wait、notify、notifyAll方法,使用它们可以实现线程之间的通信,只是平时用的较少.
wait(): 使当前线程处于等待状态,直到另外的线程调用notify或notifyAll将它唤醒
notify(): 唤醒该对象监听的其中一个线程(规则取决于JVM厂商,FILO,FIFO,随机…)
notifyAll(): 唤醒该对象监听的所有线程
锁池: 假设T1线程已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用该对象的synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前都需要先获得该对象的锁的拥有权,但是该对象的锁目前正被T1线程拥有,所以这些线程就进入了该对象的锁池中.
等待池: 假设T1线程调用了某个对象的wait()方法,T1线程就会释放该对象的锁(因为wait()方法必须出现在synchronized中,这样自然在执行wait()方法之前T1线程就已经拥有了该对象的锁),同时T1线程进入到了该对象的等待池中.如果有其它线程调用了相同对象的notifyAll()方法,那么处于该对象的等待池中的线程就会全部进入该对象的锁池中,从新争夺锁的拥有权.如果另外的一个线程调用了相同对象的notify()方法,那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的锁池.
java实现线程间通信的四种方式
1、synchronized同步:这种方式,本质上就是“共享内存”式的通信。多个线程需要访问同一个共享变量,谁拿到了锁(获得了访问权限),谁就可以执行。
2、while轮询:其实就是多线程同时执行,会牺牲部分CPU性能。
3、wait/notify机制
4、管道通信:管道流主要用来实现两个线程之间的二进制数据的传播
D. java多线程的同步控制与线程间的通信
按照下面这个运行结果(最后两行顺序不一定):
小张 用 20 元买票
小孙 用 10 元买票
小孙 买到票并拿回 5 元
小赵 用 5 元买票
小赵 买到票并拿回 0 元
小张 买到票并拿回 15 元
public class Main {
public static void main(String[] args) {
try {
TicketSeller ts = new TicketSeller();
// 张某拿着1张20元的人民币排在第一,孙某拿着1张10元的人民币排在第二,赵某拿着1张5元的人民币排在第三。
TicketBuyer zhang = new TicketBuyer(ts, "小张", 20);
Thread tZhang = new Thread(zhang);
tZhang.start();
Thread.sleep(100); // 确保买票顺序
TicketBuyer sun = new TicketBuyer(ts, "小孙", 10);
Thread tSun = new Thread(sun);
tSun.start();
Thread.sleep(100);
TicketBuyer zhao = new TicketBuyer(ts, "小赵", 5);
Thread tZhao = new Thread(zhao);
tZhao.start();
} catch (InterruptedException ex) {
}
}
}
class TicketSeller{
//电影票5元一张
private static final int TICKET_PRICE = 5;
private int fiveNumber, tenNumber, twentyNumber;
public TicketSeller(){
//售票员只有1张5元的钱
fiveNumber = 1;
tenNumber = twentyNumber = 0;
}
public synchronized int sellTicket(int receiveMoney){
int changeRequired = receiveMoney - TICKET_PRICE;
while(!prepareChange(changeRequired)){
try {
this.wait();
} catch (InterruptedException ex) {
// Do nothing
}
}
switch(receiveMoney){
case 5: fiveNumber++; break;
case 10: tenNumber++; break;
case 20: twentyNumber++; break;
default: System.out.println("错误001");
}
this.notify();
return changeRequired;
}
/**
* 给出找钱
* @param changeRequired 需要找的钱数
* @return 是否能给出
*/
private boolean prepareChange(int changeRequired) {
switch(changeRequired){
case 0:
return true;
case 5:
if(fiveNumber >= 1){
fiveNumber--;
return true;
}
break;
case 10:
// 找一张10元的
if(tenNumber >= 1){
tenNumber--;
return true;
}
// 找两张5元的
if(fiveNumber >= 2){
fiveNumber-=2;
return true;
}
break;
case 15:
// 找一张10元的+一张5元的
if(tenNumber >= 1 && fiveNumber >= 1){
tenNumber--;
fiveNumber--;
return true;
}
// 找3张5元的
if(fiveNumber >= 3){
fiveNumber-=3;
return true;
}
break;
}
return false;
}
}
class TicketBuyer implements Runnable{
private TicketSeller ts;
private int moneyAvailable;
private String myName;
public TicketBuyer(TicketSeller ts, String name, int moneyAvailable){
this.ts = ts;
this.myName = name;
this.moneyAvailable = moneyAvailable;
}
public void run() {
System.out.printf("%s 用 %d 元买票\r\n", this.myName, this.moneyAvailable);
int change = this.ts.sellTicket(this.moneyAvailable);
System.out.printf("%s 买到票并拿回 %d 元\r\n", this.myName, change);
}
}
E. Java线程之间如何通信
volatile修饰的变量具有可见性。可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,可以立即获取修改之后的值。在Java中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上进行的,之后才会同步到主存中,而加了volatile修饰符的变量则是直接读写主存。
volatile禁止指令重排 ,指令重排是指处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证各个语句的执行顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性。程序执行到volatile修饰变量的读操作或者写操作时,在其前面的操作肯定已经完成,且结果已经对后面的操作可见,在其后面的操作肯定还没有进行。
synchronized可作用于一段代码或方法,既可以保证可见性,又能够保证原子性。可见性体现在:通过synchronized或者Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存中。
原子性表现在:要么不执行,要么执行到底。从而我们可以看出volatile虽然具有可见性但是并不能保证原子性。
性能方面,synchronized关键字是防止多个线程同时执行一段代码,就会影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized。
但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。
总结
F. java中怎么实现线程通信
线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务。
Object类中相关的方法有两个notify方法和三个wait方法:
因为wait和notify方法定义在Object类中,因此会被所有的类所继承。
这些方法都是final的,即它们都是不能被重写的,不能通过子类覆写去改变它们的行为。
wait()方法
wait()方法使得当前线程必须要等待,等到另外一个线程调用notify()或者notifyAll()方法。
当前的线程必须拥有当前对象的monitor,也即lock,就是锁。
线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。
要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
G. java线程间通信问题
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadDemo {
/**
* Semaphore 就是大学操作系统里面讲的信号量, 其方法acquire和release分别对应PV操作
* AtomicInteger 是原子变量,对它的操作会转化为底层的原语(不可分割的操作),这样多线程并发对其操作就不会有问题,
* 如果是普通的int就还要加锁才能保证没问题
*/
public static void main(String[] args) throws InterruptedException {
// 用于启动另一个线程
Semaphore startThread = new Semaphore(1);
// 用于控制终止程序
AtomicInteger threadCount = new AtomicInteger(0);
for (int i = 1; i <= 10; i++) {
CountThread t = new CountThread("Thread" + i, startThread,
threadCount);
t.start();
}
}
}
class CountThread extends Thread {
// 线程标识
private String label;
// 用于启动另一个线程
private Semaphore startThread;
// 用于控制终止程序
private AtomicInteger threadCount;
public CountThread(String label, Semaphore startThread,
AtomicInteger threadCount) {
this.label = label;
this.startThread = startThread;
this.threadCount = threadCount;
}
public void run() {
try {
// 等待线程被唤醒
startThread.acquire();
System.out.println("------线程:" + label + " 开始工作------");
} catch (InterruptedException e) {
e.printStackTrace();
}
int num = 0;
while (true) {
System.out.println("线程:" + label + "计数:" + num);
// 计数到5
if (num++ == 5) {
// 唤醒另一个计数线程
startThread.release();
// 10的时候程序终止, incrementAndGet是递增(也就是++操作), 再取值
if (threadCount.incrementAndGet() == 10) {
System.exit(1);
}
}
}
}
}
研究Java并发,强烈推荐你看《Java并发编程实践》
H. java的线程之间如何进行消息传递
原生Java线程之间只抄能通过共享内存(同一个虚拟机内)来通信。当然你可以通过自己实现,使得线程看起来可以通过消息通信。比如Scala的Actor,可以通过消息传递,但Actor本身和线程是有很大不同,不过看起来具备了一些线程功能 。
I. Java中线程间怎么通讯什么叫僵死线程
JAVA直接通信 一般有个servicer端 一个client端,servicer启动后,client与servicer连接,你可以试用UDP协议或者TCP/IP协议在多线程中,线程会sleep,当程序停止时,线程仍然处于sleep中,就出现了僵死线程