Java - 并发

阅读数:57 评论数:0

跳转到新版页面

分类

python/Java

正文

一、创建线程

创建线程有四种方式:继承Thread类、实现Runnable接口、实现Callable接口、通过线程池创建。

1、继承Thread

重写run方法。

class A extends Thread{
function1;
function2;
...
public void run(){
//other code...
}
property1;
property2;
}

(1)start()方法

用于启动一个线程。

(2)sleep()方法

如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出,sleep方法不会释放该线程所拥有的资源。

(3)join()方法

当前线程调用其它线程的join方法,会阻塞当前线程,直到其他线程执行完毕。

join方法是被Synchronized关键字所修饰的,如果有两个线程同时调用另外一个线程的join方法,会有一个线程成功得到锁,而另外一个必须等待。

(4)yield()方法

此方法会让当前线程进入就绪状态,交出cpu资源,让cpu去执行其他的线程。

class JoinThread implements Runnable
{

    //重写run方法
    public void run()
    {
        for(int i = 0; i< 30;i++)
        {
            System.out.println(Thread.currentThread().getName()+"..."+i);
        }

    }

}

//main方法如下
public static void main(String[] args) throws InterruptedException
    {

        JoinThread object = new JoinThread();

        Thread t1 = new Thread(object);

        Thread t2 = new Thread(object);


        t1.start();
        t1.join();

        t2.start();

        for(int j = 0;j < 50;j++)
        {
            System.out.println(Thread.currentThread().getName()+"..."+j);
        }



    }

2、实现Runnable接口

实现Runnable接口并编写run方法。

class B implements Runnable{
function1;
function2;
...
public void run(){
//other code...
}
property1;
property2;
...
}

3、实现Callable接口

与Runnable的不同:

(1)它有返回值

(2)执行方法名为call()

class myCall implements Callable<Integer> {
  @Override
  public Integer call() throws Exception {
    //
    return 1024;
  }
}

二、Object

1、wait()

将当前线程放入object对象的等待队列中。

2、notify()

从object的等待队列中唤醒一个线程。

3、notifyAll()

唤醒object的等待队列中的所有线程。

三、Runtime类

Runtime类封装了运行时的环境,每个Java应用程序都有一个Runtime类实例,使用应用程序能够与其运行环境相连接。通过Runtime.getRuntime()获取Runtime类的实例。Runtime类使用的是单例模式。

1、Runtime.getRuntime().addShutdownHook

这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的所有通过这个方法添加的钩子,当系统执行完这些钩子后,jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作。

四、java.util.concurrent包

Java 5添加了一个新的包到Java平台,java.util.concurrnet包。这个包包含有一系列能够让Java的并发编程变得更加简单轻松的类。

1、BlockingQueue 阻塞队列

一个线程将会持续生产新对象并将其插入到队列之中,直到队列达到它所能容纳的临界点。也就是说,它是有限的,如果该阻塞队列到达了其临界点,负责生产的线程将会在往里面插入新对象时发生阻塞。

负责消费的线程将会一直从该阻塞队列中拿出对象。如果消费线程尝试去从一个空的队列中提取对象的时候,这个消费线程将会处于阻塞中,直到一个生产线程把一个对象丢进队列。

BlockingQueue是个接口,你需要使用它的实现之一使用BlockingQueue

(1)ArrayBlockingQueue,是一个有界的阻塞队列。

(2)DelayQueue,对元素进行持有直到一个特定的延迟到期,注入其中的元素必须实现 java.util.concurrnet.Delayed接口。

(3)LinkedBlockingQueue,可以选择一个上限。

(4)PriorityBlockingQueue,无界队列,所有插入到PriorityBlockingQueue的元素必须实现java.lang.Comparable接口。

(5)SynchronousQueue,它的内部同时只能容纳单个元素。

2、BlockingDeque 阻塞双端队列

双端队列是一个你可以从任意一端插入或提取元素的队列。这也是一个接口,它的实现类有LinkedBlockingDeque。

3、ConcurrentMap 并发Map

这是一个接口,其实现类为ConcurrentHashMap。

(1)ConcurrentHashMap的putIfAbsent方法,在key不存在的时候加一个值,如果key存在就不放入。

4、CountDownLatch 闭锁

它允许一个或多个线程等待一系列指定操作的完成。

CountDownLatch以一个给定的数量初始化。countDown()每被调用一次,这一数量就减一。通过调用await()方法之一,线程可以阻塞等待这一数量到达零。

5、CyclicBarrier

这是一个同步机制,它能够处理一些算法的线程的同步问题。换句话说它就是一个所有线程必须等待的一栅栏,直到所有的线程都到达这里,然后所有线程才可以继续做其他事情。

6、Exchanger

表示一种两个线程可以进行互相交换对象的点。

7、Semaphore信息量

(1)acquire()

(2)elease()

信号量主要有两种用途:

(1)保护一个重要的(代码)部分防止超过N个线程进入。

(2)在两个线程之间发送信号

8、ExecutorService

类似于一个线程池。这是一个接口,它的实现类有ThreadPoolExecutor和ScheduledThreadPoolExecutor。

ThreadPoolExecutor包含的线程池的数量由下面变量决定:

(1)corePoolSize

(2)maximumPoolSize

当一个任务委托给线程池时,如果线程数理低于corePoolSize,一个新的线程将被创建,即使池中可能尚有空闲线程。

如果内部 任务队列已满,而且有至少corePoolSize正在运行,但是运行线程的数量低于maximumPoolSize,一个新的线程将被创建。

9、ForkJoinPool

在Java7中被引入,这是一个特殊的线程池,它的设计是为更好的配合分叉-合并任务的工作。

10、Lock 锁

它是一个类似于synchronized块的线程同步机制。但是Lock比synchronized块更加灵活、精细。

(1)synchroinzed代码块不能够保证进入访问等待的线程的先后顺序。

(2)不能够传递任何参数给一个synchronized代码块的入口

(3)synchronized块必须被完整地包含在单个方法里,而一个Lock对象的可以把它的lock和unlock方法的调用放在不同的方法里。

这是一个接口,它的实现类是ReetrantLock。

12、ReadWriteLock读定锁

它能够允许多个线程在同一时间对某特定资源进行读取,但同一时间内只有一个线程对其进行写入。这是一个接口,它的实现类是ReentrantReadWriteLock。

13、原子变量

AtomicBoolean

AtomicInteger

AtomicLong

AtomicReference

(1)get(),返回当前的引用。

(2)compareAndSet(expect, update),如果当前值与给定的expect相等(是引用相等),更新为指定的update值。

(3)getAndSet(newValue),

原子地设为给定值并返回旧值。

14、ConcurrentNavigableMap

heapMap(T toKey):返回一个包含小于给定toKey的key的子map。

tailMap(T fromKey):返回一个包含了不小于给定fromKey的key的子map。

subMap(T from,T to):返回一个键值介于from(包含)和to(不包含)之间的子map。

15、ConcurrentLinkedDequeue

Java 7中引入的类,它实现了一个非阻塞并发列表,如果操作不能立即完成,会抛出异常或者返回一个null值。

(1)getFirst()和getLast()这些方法返回分别从列表中第一个和最后一个元素。他们不会从列表中删除返回的元素。如果列表是空的,这些方法抛出一个NoSuchElementException。

(2)peek(),peekFirst(),peekLast()这些方法返回列的第一个和最后一个元素。他们不会从列表中删除返回的元素。如果列表为空,这些方法返回一个null值。

(3)remove(), removeFirst(), removeLast():这此方法返回列表的第一个和最后一个元素。他们从列表中移除返回的元素。如果列表是空的,这些方法抛出一个NoSuchElementException。

(4)像大多数其他并发集合类实现,这个类不允许null元素的使用。

16、CopyOnWrite

从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。

读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。

CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性,所以如果你希望写入的数据,马上能读到,请不要使用CopyOnWrite容器。