×

线程通信方式 线程

如何在学习Java过程中实现线程之间的通信?java中线程同步的几种方法

admin admin 发表于2022-06-12 20:15:25 浏览120 评论0

抢沙发发表评论

如何在学习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、管道通信:管道流主要用来实现两个线程之间的二进制数据的传播


java中线程同步的几种方法


线程同步主要有以下种方法(示例中是实现计数的功能):

1、同步方法,即使用synchronized关键字修饰方法,例如:

public synchronized void add(int c){...}

2、同步代码块,即有synchronized关键字修饰的语句块,例如:

public void addAndGet(int c){
    synchronized(this){
      count += c;
    }
}

3、使用特殊域变量(volatile)实现线程同步,该方法不能保证绝对的同步。

例如:private volatile int count = 0;

4、使用锁实现线程同步,例如:

private Lock lock = new ReentrantLock();
  public void add(int c) {  
        lock.lock();//上锁  
        try{  
            count += c;  
        }finally{  
            lock.unlock();//解锁  
        }  
    }

5、使用原子变量实现线程同步,在java的util.concurrent.atomic包中提供了创建了原子类型变量的工具类,例如:

private AtomicInteger count= new AtomicInteger(1);
public void add(int c) {
    count.addAndGet(c);
}

6、使用局部变量实现线程同步,如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。-线程

ThreadLocal 类的常用方法

new ThreadLocal《T》() : 创建一个线程本地变量

get() : 返回此线程局部变量的当前线程副本中的值

initialValue() : 返回此线程局部变量的当前线程的“初始值“

set(T value) : 将此线程局部变量的当前线程副本中的值设置为value

示例代码:

private static ThreadLocal《Integer》 count= new ThreadLocal《Integer》(){
          @Override
          protected Integer initialValue(){ 
              return 1;
             }
     };            
 
public void add(int c){
                count.set(count.get() + c);
    }

7、使用阻塞队列实现,例如LinkedBlockingQueue,具体使用可百度LinkedBlockingQueue的用法或查看java文档。


什么是java多线程详解


线程对象是可以产生线程的对象。比如在Java平台中Thread对象,Runnable对象。线程,是指正在执行的一个指点令序列。在java平台上是指从一个线程对象的start()开始,运行run方法体中的那一段相对独立的过程。相比于多进程,多线程的优势有:
(1)进程之间不能共享数据,线程可以;
(2)系统创建进程需要为该进程重新分配系统资源,故创建线程代价比较小;
(3)Java语言内置了多线程功能支持,简化了java多线程编程。
一、创建线程和启动
(1)继承Thread类创建线程类
通过继承Thread类创建线程类的具体步骤和具体代码如下:
• 定义一个继承Thread类的子类,并重写该类的run()方法;
• 创建Thread子类的实例,即创建了线程对象;
• 调用该线程对象的start()方法启动线程。
复制代码
class SomeThead extends Thraad {
public void run() {
//do something here
}
}

public static void main(String args){
SomeThread oneThread = new SomeThread();
步骤3:启动线程:
oneThread.start();
}
复制代码
(2)实现Runnable接口创建线程类
通过实现Runnable接口创建线程类的具体步骤和具体代码如下:
• 定义Runnable接口的实现类,并重写该接口的run()方法;
• 创建Runnable实现类的实例,并以此实例作为Thread的target对象,即该Thread对象才是真正的线程对象。
复制代码
class SomeRunnable implements Runnable {
public void run() {
//do something here
}
}
Runnable oneRunnable = new SomeRunnable();
Thread oneThread = new Thread(oneRunnable);
oneThread.start();
复制代码
(3)通过Callable和Future创建线程
通过Callable和Future创建线程的具体步骤和具体代码如下:
• 创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
• 创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
• 使用FutureTask对象作为Thread对象的target创建并启动新线程。
• 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值其中,Callable接口(也只有一个方法)定义如下:
复制代码
public interface Callable {
V call() throws Exception;
}
步骤1:创建实现Callable接口的类SomeCallable(略);
步骤2:创建一个类对象:
Callable oneCallable = new SomeCallable();
步骤3:由Callable创建一个FutureTask对象:
FutureTask oneTask = new FutureTask(oneCallable);
注释: FutureTask是一个包装器,它通过接受Callable来创建,它同时实现了 Future和Runnable接口。
步骤4:由FutureTask创建一个Thread对象:
Thread oneThread = new Thread(oneTask);
步骤5:启动线程:
oneThread.start();
-线程通信方式