Java - 并发
阅读数:231 评论数:0
跳转到新版页面分类
python/Java
正文
一、创建线程
创建线程有四种方式:继承Thread类、实现Runnable接口、实现Callable接口、通过线程池创建。
重写run方法。
class A extends Thread{
function1;
function2;
...
public void run(){
//other code...
}
property1;
property2;
}
(1)常用方法
start方法 | 用于启动一个线程。 |
sleep方法 | 如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出,sleep方法不会释放该线程所拥有的资源。 |
join方法 |
当前线程调用其它线程的join方法,会阻塞当前线程,直到其他线程执行完毕。 join方法是被Synchronized关键字所修饰的,如果有两个线程同时调用另外一个线程的join方法,会有一个线程成功得到锁,而另外一个必须等待。 |
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);
}
}
实现Runnable接口并编写run方法。
class B implements Runnable{
function1;
function2;
...
public void run(){
//other code...
}
property1;
property2;
...
}
与Runnable的不同:
(1)它有返回值
(2)执行方法名为call()
class myCall implements Callable<Integer> {
@Override
public Integer call() throws Exception {
//
return 1024;
}
}
二、Object中相关的并发控制方法
wait | 将当前线程放入object对象的等待队列中。 |
notify | 从object的等待队列中唤醒一个线程。 |
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的并发编程变得更加简单轻松的类。
一个线程将会持续生产新对象并将其插入到队列之中,直到队列达到它所能容纳的临界点。也就是说,它是有限的,如果该阻塞队列到达了其临界点,负责生产的线程将会在往里面插入新对象时发生阻塞。
负责消费的线程将会一直从该阻塞队列中拿出对象。如果消费线程尝试去从一个空的队列中提取对象的时候,这个消费线程将会处于阻塞中,直到一个生产线程把一个对象丢进队列。
BlockingQueue是个接口,你需要使用它的实现之一使用BlockingQueue
ArrayBlockingQueue | 是一个有界的阻塞队列 |
DelayQueue | 对元素进行持有直到一个特定的延迟到期,注入其中的元素必须实现 java.util.concurrnet.Delayed接口。 |
LinkedBlockingQueue | 可以选择一个上限 |
PriorityBlockingQueue | 无界队列,所有插入到PriorityBlockingQueue的元素必须实现java.lang.Comparable接口 |
SynchronousQueue | 它的内部同时只能容纳单个元素。 |
双端队列是一个你可以从任意一端插入或提取元素的队列。这也是一个接口,它的实现类有LinkedBlockingDeque。
这是一个接口,其实现类为ConcurrentHashMap。
(1)ConcurrentHashMap
putIfAbsent方法 | 在key不存在的时候加一个值,如果key存在就不放入。 |
它允许一个或多个线程等待一系列指定操作的完成。
CountDownLatch以一个给定的数量初始化。countDown()每被调用一次,这一数量就减一。通过调用await()方法,线程可以阻塞等待这一数量到达零。
这是一个同步机制,它能够处理一些算法的线程的同步问题。换句话说它就是一个所有线程必须等待的一栅栏,直到所有的线程都到达这里,然后所有线程才可以继续做其他事情。
表示一种两个线程可以进行互相交换对象的点。
(1)acquire()
(2)release()
信号量主要有两种用途:
(1)保护一个重要的(代码)部分防止超过N个线程进入。
(2)在两个线程之间发送信号
类似于一个线程池。这是一个接口,它的实现类有ThreadPoolExecutor和ScheduledThreadPoolExecutor。
ThreadPoolExecutor包含的线程池的数量由下面变量决定:
(1)corePoolSize
(2)maximumPoolSize
当一个任务委托给线程池时,如果线程数理低于corePoolSize,一个新的线程将被创建,即使池中可能尚有空闲线程。
如果内部 任务队列已满,而且有至少corePoolSize正在运行,但是运行线程的数量低于maximumPoolSize,一个新的线程将被创建。
在Java7中被引入,这是一个特殊的线程池,它的设计是为更好的配合分叉-合并任务的工作。
它是一个类似于synchronized块的线程同步机制。但是Lock比synchronized块更加灵活、精细。
(1)synchroinzed代码块不能够保证进入访问等待的线程的先后顺序。
(2)不能够传递任何参数给一个synchronized代码块的入口
(3)synchronized块必须被完整地包含在单个方法里,而一个Lock对象的可以把它的lock和unlock方法的调用放在不同的方法里。
这是一个接口,它的实现类是ReetrantLock。
它能够允许多个线程在同一时间对某特定资源进行读取,但同一时间内只有一个线程对其进行写入。这是一个接口,它的实现类是ReentrantReadWriteLock。
AtomicBoolean | |
AtomicInteger | |
AtomicLong | |
AtomicReference |
get() | 返回当前的引用。 |
compareAndSet(expect, update) | 如果当前值与给定的expect相等(是引用相等),更新为指定的update值。 |
getAndSet(newValue) | 原子地设为给定值并返回旧值。 |
heapMap(T toKey) | 返回一个包含小于给定toKey的key的子map。 |
ailMap(T fromKey) | 返回一个包含了不小于给定fromKey的key的子map。 |
subMap(T from,T to) | 返回一个键值介于from(包含)和to(不包含)之间的子map。 |
Java 7中引入的类,它实现了一个非阻塞并发列表,如果操作不能立即完成,会抛出异常或者返回一个null值。
(1)getFirst()和getLast()这些方法返回分别从列表中第一个和最后一个元素。他们不会从列表中删除返回的元素。如果列表是空的,这些方法抛出一个NoSuchElementException。
(2)peek(),peekFirst(),peekLast()这些方法返回列的第一个和最后一个元素。他们不会从列表中删除返回的元素。如果列表为空,这些方法返回一个null值。
(3)remove(), removeFirst(), removeLast():这此方法返回列表的第一个和最后一个元素。他们从列表中移除返回的元素。如果列表是空的,这些方法抛出一个NoSuchElementException。
(4)像大多数其他并发集合类实现,这个类不允许null元素的使用。
从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。
读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。
CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性,所以如果你希望写入的数据,马上能读到,请不要使用CopyOnWrite容器。