Java concurrent

Overview

Java平台包含一系列并发实用程序。 这些类被设计成在构建并发类或应用程序时用作构建块。 就像集合框架通过提供常用数据结构的实现简化了内存数据的组织和操作一样,并发实用程序通过提供并发设计中常用的构建块的实现来简化并发类的开发。 并发实用程序包括:

  • 高性能,灵活的线程池;
  • 异步执行任务框架;
  • 同步实用程序(如计算信号量);
  • 原子变量;
  • 锁;
  • 和条件变量

使用并发实用程序而不是自己开发诸如线程池之类的组件,提供了许多优点:

  • 减少编程工作量。 使用标准类比自己开发它更容易。
  • 提高性能。 java并发API由并发和性能专家开发并进行了同行评审; 与典型的实现相比,这些实现可能会更快,更具可扩展性,即使是熟练的开发人员也是如此。
  • 增加可靠性。 开发并发类很困难 - Java语言(synchronized,volatile,wait(),notify()和notifyAll())提供的低级并发基元很难正确使用,并且使用这些工具的错误可能会很困难 检测和调试。 通过使用标准化,经过广泛测试的并发构建模块,可以消除诸如死锁,饥饿,竞态条件或过度上下文切换等线程危险的潜在来源。 对并发实用程序进行了仔细审计,以确定是否存在死锁,饥饿和竞争状况。
  • 改进的可维护性。 使用标准库类的程序比那些依赖复杂的第三方类的程序更容易理解和维护。
  • 提高生产力。 开发人员很可能已经了解了标准库类,因此不需要了解特定并发组件的API和行为。 此外,当并发应用程序构建在可靠,经过充分测试的组件上时,它们的调试更为简单。

简而言之,使用并发实用程序来实现并发应用程序可以帮助您的程序更清晰,更短,更快,更可靠,更具可扩展性,更易于编写,更易于阅读和维护。

并发实用程序包括:

  • 任务调度框架。 Executor接口根据一组执行策略标准化调用,调度,执行和控制异步任务。 提供了实现,使任务能够在提交线程,单个后台线程(如Swing中的事件),新创建的线程或线程池中执行,开发人员可以创建自定义的Executor实现,支持任意 执行政策。 内置实现提供可配置的策略,如队列长度限制和饱和策略,可通过防止资源使用失控来提高应用程序的稳定性。

  • Fork/join框架。 基于ForkJoinPool类,这个框架是Executor的一个实现。 它旨在使用工作线程池有效地运行大量任务。 A work-stealing技术用于保持所有工作线程繁忙,以充分利用多个处理器。

  • 并发容器。 添加了几个集合类,包括新的Queue,BlockingQueue和BlockingDeque接口,以及Map,List和Queue的高性能并发实现。 有关更多信息,请参阅集合框架指南。

  • 原子变量。 提供的工具类可以自动操纵单个变量(原始类型或引用),提供高性能的原子算术和比较和设置方法。 java.util.concurrent.atomic包中的原子变量实现提供比使用同步(在大多数平台上)可用的性能更高的性能,使它们对于实现高性能并发算法以及方便地实现计数器和序列号生成器非常有用。

  • 同步器。 通用同步类(包括信号量,屏障,锁存器,相位器和交换器)有助于线程之间的协调。

  • 锁。 虽然通过synchronized关键字将锁定内置到Java语言中,但内置监视器锁定存在许多限制。 java.util.concurrent.locks包提供了与同步相同的内存语义的高性能锁实现,并且它还支持在尝试获取锁时指定超时,每个锁具有多个条件变量,nonnested(“hand-over-hand“)持有多个锁,并支持中断正在等待获取锁的线程。

  • 纳秒粒度时序。 System.nanoTime方法允许访问纳秒粒度时间源,以进行相对时间测量和接受超时的方法(例如BlockingQueue.offer,BlockingQueue.poll,Lock.tryLock,Condition.await和Thread.sleep)可以 以纳秒为单位取超时值。 System.nanoTime方法的实际精度取决于平台。

进程与线程的区别

进程
A process has a self-contained execution environment. A process generally has a complete, private set of basic run-time resources; in particular, each process has its own memory space.

Processes are often seen as synonymous with programs or applications. However, what the user sees as a single application may in fact be a set of cooperating processes. To facilitate communication between processes, most operating systems support Inter Process Communication (IPC) resources, such as pipes and sockets. IPC is used not just for communication between processes on the same system, but processes on different systems.

Most implementations of the Java virtual machine run as a single process. A Java application can create additional processes using a ProcessBuilder object. Multiprocess applications are beyond the scope of this lesson.

线程
Threads are sometimes called lightweight processes. Both processes and threads provide an execution environment, but creating a new thread requires fewer resources than creating a new process.

Threads exist within a process — every process has at least one. Threads share the process’s resources, including memory and open files. This makes for efficient, but potentially problematic, communication.

Multithreaded execution is an essential feature of the Java platform. Every application has at least one thread — or several, if you count “system” threads that do things like memory management and signal handling. But from the application programmer’s point of view, you start with just one thread, called the main thread. This thread has the ability to create additional threads, as we’ll demonstrate in the next section.

线程对象

定义并启动一个线程

public class HelloRunnable implements Runnable {

    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}
public class HelloThread extends Thread {

    public void run() {
        System.out.println("Hello from a thread!");
    }

    public static void main(String args[]) {
        (new HelloThread()).start();
    }

}

暂停执行

public class SleepMessages {
    public static void main(String args[])
        throws InterruptedException {
        String importantInfo[] = {
            "Mares eat oats",
            "Does eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };

        for (int i = 0;
             i < importantInfo.length;
             i++) {
            //Pause for 4 seconds
            Thread.sleep(4000);
            //Print a message
            System.out.println(importantInfo[i]);
        }
    }
}

中断

for (int i = 0; i < importantInfo.length; i++) {
    // Pause for 4 seconds
    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // We've been interrupted: no more messages.
        return;
    }
    // Print a message
    System.out.println(importantInfo[i]);
}
for (int i = 0; i < inputs.length; i++) {
    heavyCrunch(inputs[i]);
    if (Thread.interrupted()) {
        // We've been interrupted: no more crunching.
        return;
    }
}

In this simple example, the code simply tests for the interrupt and exits the thread if one has been received. In more complex applications, it might make more sense to throw an InterruptedException:

if (Thread.interrupted()) {
    throw new InterruptedException();
}

活跃度

死锁

public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s"
                + "  has bowed to me!%n", 
                this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend alphonse = new Friend("Alphonse");
        final Friend gaston = new Friend("Gaston");
        new Thread(new Runnable() {
            public void run() { alphonse.bow(gaston); }
        }).start();
        new Thread(new Runnable() {
            public void run() { gaston.bow(alphonse); }
        }).start();
    }
}

饥饿和活锁

防护块

高并发对象

锁对象

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;

public class Safelock {
    static class Friend {
        private final String name;
        private final Lock lock = new ReentrantLock();

        public Friend(String name) {
            this.name = name;
        }

        public String getName() {
            return this.name;
        }

        public boolean impendingBow(Friend bower) {
            Boolean myLock = false;
            Boolean yourLock = false;
            try {
                myLock = lock.tryLock();
                yourLock = bower.lock.tryLock();
            } finally {
                if (! (myLock && yourLock)) {
                    if (myLock) {
                        lock.unlock();
                    }
                    if (yourLock) {
                        bower.lock.unlock();
                    }
                }
            }
            return myLock && yourLock;
        }

        public void bow(Friend bower) {
            if (impendingBow(bower)) {
                try {
                    System.out.format("%s: %s has"
                        + " bowed to me!%n", 
                        this.name, bower.getName());
                    bower.bowBack(this);
                } finally {
                    lock.unlock();
                    bower.lock.unlock();
                }
            } else {
                System.out.format("%s: %s started"
                    + " to bow to me, but saw that"
                    + " I was already bowing to"
                    + " him.%n",
                    this.name, bower.getName());
            }
        }

        public void bowBack(Friend bower) {
            System.out.format("%s: %s has" +
                " bowed back to me!%n",
                this.name, bower.getName());
        }
    }

    static class BowLoop implements Runnable {
        private Friend bower;
        private Friend bowee;

        public BowLoop(Friend bower, Friend bowee) {
            this.bower = bower;
            this.bowee = bowee;
        }

        public void run() {
            Random random = new Random();
            for (;;) {
                try {
                    Thread.sleep(random.nextInt(10));
                } catch (InterruptedException e) {}
                bowee.bow(bower);
            }
        }
    }


    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new BowLoop(alphonse, gaston)).start();
        new Thread(new BowLoop(gaston, alphonse)).start();
    }
}

Questions and Exercises: Concurrency

Questions
Can you pass a Thread object to Executor.execute? Would such an invocation make sense?
Exercises
Compile and run BadThreads.java:

public class BadThreads {

    static String message;

    private static class CorrectorThread
        extends Thread {

        public void run() {
            try {
                sleep(1000); 
            } catch (InterruptedException e) {}
            // Key statement 1:
            message = "Mares do eat oats."; 
        }
    }

    public static void main(String args[])
        throws InterruptedException {

        (new CorrectorThread()).start();
        message = "Mares do not eat oats.";
        Thread.sleep(2000);
        // Key statement 2:
        System.out.println(message);
    }
}

The application should print out “Mares do eat oats.” Is it guaranteed to always do this? If not, why not? Would it help to change the parameters of the two invocations of Sleep? How would you guarantee that all changes to message will be visible in the main thread?

Modify the producer-consumer example in Guarded Blocks to use a standard library class instead of the Drop class.

参考文档

http://cn6.pw/java/concurrency.html
https://docs.oracle.com/javase/tutorial/essential/concurrency/QandE/questions.html

练习题

https://www.cnblogs.com/huajiezh/p/5790942.html
https://www.cnblogs.com/bsjl/p/7693029.html
https://www.cnblogs.com/Jixiangwei/p/6822334.html
http://blog.csdn.net/u010823625/article/details/53349445
http://cmsblogs.com/?hmsr=toutiao.io&p=2071&utm_medium=toutiao.io&utm_source=toutiao.io

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值