Java多线程与线程间的通信

进程和线程

操作系统有多个运行的软件

一个运行中的软件可能包含多个进程

一个运行中的进程可能包含多个线程

线程

按代码顺序执行下来,执行完毕就结束的一条线

UI线程不会结束,因为它在初始化完毕后就执行死循环,循环的内容是刷新界面

多线程使用

Thread
Thread thread1 = new Thread(){
    @Override
    public void run() {
        System.out.println("线程执行了...");
    }
};
thread1.start();
Runnable
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("线程执行了...");
    }
};
Thread thread2 = new Thread(runnable);
thread2.start();
ThreadFactory
ThreadFactory threadFactory = new ThreadFactory() {
   AtomicInteger count = new AtomicInteger(0);
    @Override
    public Thread newThread(Runnable r) {
        count.incrementAndGet();
        return new Thread(r, "Thread-" + count);
    }
};
threadFactory.newThread(runnable1).start();
threadFactory.newThread(runnable2).start();
Executor线程池

常用:newCachedThreadPool() 可缓存的线程池

ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.execute(runnable1);
threadPool.execute(runnable2);

短时批量处理:newFixedThreadPool()

ExecutorService threadPool2 = Executors.newFixedThreadPool(20);
threadPool2.execute(runnable1);
threadPool2.execute(runnable2);
threadPool2.shutdown();// 关闭线程池

Callable 和 Future

Callable<String> callable = new Callable<String>(){
    @Override
    public String call() throws Exception {
        Thread.sleep(2000);
        return "Done";
    }
};
ExecutorService threadPool = Executors.newCachedThreadPool();
Future<String> future = threadPool.submit(callable);// 把任务提交到线程池中执行,不会阻塞当前线程
try {
    while(true) {
        // 判断任务是否完成,如果完成再去获取结果
        if (future.isDone()) {
            String result = future.get();// 如果任务未完成,会阻塞
            System.out.println("result:" + result);
        }
        // 执行其他任务
    }
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

线程同步和线程安全

线程的同步控制是为了保护共有资源

synchronized
synchronized方法
private synchronized void method(){// 直接给方法上加synchronized,给方法加上当前对象的锁
    
}

synchrinized代码块
private void method(){
    synchronized (this){// this指代当前对象,和直接在方法synchronized效果一样
        
    }
}

private final Object monitor1 = new Object();// 监视器,当前代码没有执行完时,不会释放锁
private final Object monitor2 = new Object();

private void method(){
    synchronized (monitor1){
        synchronized (monitor2){
            
        }
    }
}

synchronized本质

保证方法内部或代码块内部资源(数据)的互斥访问。在同一时间、由同一个Monitor监视的代码,最多有一个线程在访问

保证线程之间对监视资源的数据同步。任何线程在获取到Monitor后的第一时间,会先将共享内存中的数据复制到自己的缓存中,任何线程在释放Monitor的第一时间,会先将缓存中的数据复制到共享内存中。


volatile

加了 volatile 关键字的操作具有同步性,因此 valatile 可以看做是简化版的 synchronized.


volatile 只对基本类型(byte、char、short、int、long、float、double、boolean)的赋值操作和对象的引用赋值操作有效,如果修改User.name是不能保证同步的。

volatile依然解决不了++的原子性问题。


AtomicInteger、AtomicBoolean等,作用和 volatile基本一致,可以看做是通用版的volatile


Lock/ReentrantReadWriteLock

Lock

使用起来更灵活,同时也麻烦一些

private int value;
private final Lock lock = new ReentrantLock();

private void count() {
    lock.lock();
    try {
        value++;
    } finally {
        lock.unlock();
    }
}

ReadWriteLock
private int value;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();// 读操作的锁
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();// 写操作的锁

private void count(){
    writeLock.lock();
    try{
        value++;
    }finally {
        writeLock.unlock();
    }
}

private void print() {
    readLock.lock();
    try{
        System.out.println(value);
    } finally {
        readLock.unlock();
    }
}

线程安全问题的本质

在多个线程访问共同资源时,在某一个线程对资源进行写操作的中途,其他线程对这个写了一半的资源进行了读操作,或者基于这个写了一半的资源进行了写操作,导致出现了数据错误。


锁机制的本质

通过对共享资源进行访问控制,让同一时间只有一个线程可以访问资源,保证了数据的准确性。

不论是线程安全问题,还是针对线程安全问题所衍生出的锁机制,它们的核心都是在于共享资源,而不是某个方法或者某几行代码。


线程间通信

一个线程终止另外一个线程

Thread.stop() 不知道停止线程当前执行到哪里,造成结果不可预期

Thread.interrupt() 中断线程,给目标线程加了一个标记,不立即,不强制,需要目标线程配合处理,目标线程内部自己通过 isInterrupt() 或 Thread.interrupted() 来判断 当前线程是否被中断,但使用 Thread.interrupted() 判断会把中断标记重置为false


InterruptedException

如果在线程等待状态(Thread.sleep)时被中断(interrupt),直接结束等待过程,抛出InterruptedException,同时把中断标记重置为false


Object.wait() 和 Object.notify() / notifyAll()

在未达到目标时 wait()

设置完成后 notifyAll()

wait() 和 notify() / notifyAll() 都需要放在同步代码块里,在一个互斥的共享资源中wait等待,当操作结束后调用notify唤醒等待


Thread.join()

让一个线程插在自己前面,调用目标线程的join,就会等待目标完成后自己线程再执行

Thread.yield()

暂时让出自己的时间片给同优先级的线程

ConditionVariable

线程操作经常用到wait和notify,用起来比较繁琐,Android封装好了一个ConditionVariable类,用于提供线程同步

ConditionVariable cv = new ConditionVariable();
cv.block();// 锁住当前线程
cv.open();// 解锁被锁住的线程

CountDownLatch

是一个同步工具类,用来协调多个线程之间的同步,能够使一个线程在等待另外一些线程执行完后,再继续执行。

实现在某一线程等待n个线程执行完毕在运行
ExecutorService threadPool = Executors.newCachedThreadPool();
CountDownLatch countDownLatch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " 运行了...");
                Thread.sleep(2000);
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    threadPool.execute(runnable);
}
try {
    countDownLatch.await();
    System.out.println(Thread.currentThread().getName() + " 运行了...");
} catch (InterruptedException e) {
    e.printStackTrace();
}

实现多个线程开始执行任务的并行性
ExecutorService threadPool = Executors.newCachedThreadPool();
CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i = 0; i < 3; i++) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                countDownLatch.await();// 等待任务的执行
                System.out.println(Thread.currentThread().getName() + " 运行了...");
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    threadPool.execute(runnable);
}

try {
    Thread.sleep(2000);
    countDownLatch.countDown();// 唤醒其他线程开始执行任务
} catch (InterruptedException e) {
    e.printStackTrace();
}

CyclicBarrier

循环屏障,等待所有的任务都到达再执行任务,屏障可以循环使用

public class CyclicBarrierDemo {

    static class TaskThread extends Thread {
        
        CyclicBarrier barrier;
        
        public TaskThread(CyclicBarrier barrier) {
            this.barrier = barrier;
        }
        
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println(getName() + " 到达栅栏 A");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 A");
                
                Thread.sleep(2000);
                System.out.println(getName() + " 到达栅栏 B");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 B");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        int threadNum = 5;
        CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 完成最后任务");
            }
        });
        
        for(int i = 0; i < threadNum; i++) {
            new TaskThread(barrier).start();
        }
    }
    
}

Semaphore

信号量,可以用来控制访问特定资源的线程数量

public class SemaphoreTest {
    private static final int COUNT = 40;
    private static Executor executor = Executors.newFixedThreadPool(COUNT);
    private static Semaphore semaphore = new Semaphore(10);// 存储数据控制最大10个线程
  
    public static void main(String[] args) {
        for (int i=0; i< COUNT; i++) {
            executor.execute(new ThreadTest.Task());
        }
    }

    static class Task implements Runnable {
        @Override
        public void run() {
            try {
                //读取文件操作
                semaphore.acquire();// 获取一个信号量
                // 存数据过程
                semaphore.release();// 释放一个信号量
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值