java编程思想—并发编程小结一
来源:互联网 发布:联通ssr免流端口2017 编辑:程序博客网 时间:2024/06/06 00:51
1实现方法
1实现runnable接口,重写run方法,调用run方法
2new thread类,传入runnable接口实现类,使用thread的start方法,
2一些方法
yield:暂停当前正在执行的线程对象,并执行其它线程
wait:线程等待,并释放锁,一般在sychronized块里面,一般放在while循环中。生产者消费者模型中,当队列已满的时候,生产者wait,队列为空,消费者wait
notify:唤醒一个正在等待的进程。
notifyall:唤醒所有等待的线程,基于信号量会比较明显
sleep:阻塞一段时间
3executor
简化并发编程,替代了thread,对任务进行管理
ExecutorService 指定如何调用runnable对象。 通过executor的静态方法创建 execute执行,shutdown结束
1cachedthreadpool 为每个任务都创建一个线程。
2fixedthreadpool 使用有限线程集来执行所提交到任务
3singlethreadexecutor 排队执行
4callable<>,实现call方法
runnable是独立任务,不返回任何值,callable对象通过call方法来返回值
class TaskWithResult implements Callable<Integer>{
private int id;
public TaskWithResult(int id){
this.id=id;
}
@Override
public Integer call() throws Exception {
Thread.sleep(5000);
return id;
}
}
public class CallableDemo {
public static void main(String args[]){
ExecutorService exec = Executors.newCachedThreadPool();
ArrayList<Future<Integer>> results=new ArrayList<Future<Integer>>();
for (int i=0;i<10;i++)
results.add(exec.submit(new TaskWithResult(i)));
for (Future<Integer> fs:
results) {
try {
System.out.println(fs.isDone());//判断fs是否已经做完
System.out.println(fs.get());//自动阻塞,等到fs.isDone()为true时执行。
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
exec.shutdown();
}
}
}
}
5 sleep
可以抛出,InterruptedException.异常不能夸线程传播回main(),所以必须在本处进行捕获
6 priority
Thread.currentThread()可以获取当前的线程,使用setPriority可以设置优先级,最大为10,最小为1,默认为5
7 daemon
它并不属于程序中不可或缺的一部分,t2是守护线程。在“主线程main”和“子线程t1”(它们都是用户线程)执行完毕,只剩t2这个守护线程的时候,JVM自动退出。
8 yield
线程让步,就是释放cpu执行,让所有的线程可以一起来抢,可能还是本线程抢到。yield与wait最大区别在于是否会释放锁,
9 join
1A线程调用某个执行中的线程B的join方法,则A线程必须要等待B线程执行完毕后才可以执行,也就是此处变成了串行,而非并行。
下面的例子就说明这个问题,同时,调用B的interrupt方法,可以使得B线程的sleep过程被中断,并抛出InterruptedException
class Sleeper extends Thread{
private int duration;
public Sleeper(String name,int sleepTime){
super(name);
duration = sleepTime;
start();
}
public void run(){
try{
sleep(duration);
}catch(InterruptedException e){
System.out.println(getName()+"was interrupted."+"isInterrupted():"+isInterrupted());
return;
}
System.out.println(getName()+"has awakened");
}
}
class Joiner extends Thread{
private Sleeper sleeper;
public Joiner(String name,Sleeper sleeper){
super(name);
this.sleeper=sleeper;
start();
}
public void run(){
try{
sleeper.join();
}catch(InterruptedException e){
System.out.println("Interrupted");
}
System.out.println(getName()+"join completed");
}
}
public class JoinThread {
public static void main(String[] args){
Sleeper sleepy = new Sleeper("sleepy",3000),
grumpy = new Sleeper("grumpy",1500);
Joiner dopey = new Joiner("Dopey",sleepy),
doc = new Joiner("doc",grumpy);
grumpy.interrupt();
}
}
10 线程中的异常
下面所示的例子就是说明,尽管主线程中捕获子线程,但是却失败了。
class T1 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
//try {
throw new RuntimeException("zhang");
//} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
// System.out.println("run method catch");
//}
}
}
public class ThreadException {
public static void main(String args[]){
try{
Thread t1 = new Thread(new T1());
t1.start();
}catch(Exception e){
e.printStackTrace();
System.out.println("eeee");
}
}
}
10 方法上面直接加锁,不加参数
一种方式认为通过一个类new出多个对象来执行,因此加锁的时候考虑到使用类型锁。
另一种方式直接在方法上加锁,好像没有用,其实不然
往往我们需要做的是,将一个对象传入多个线程中作为参数执行,这时肯定就有问题了。
get 和 set方法也是如此,多个线程操作同一个对象,这时使用synchronized关键字,不加参数及代码块,使用的是对象锁
11 lock
设置成static的LOCK,lock.lock()-------------lock.unlock()
作用和synchronized关键字效果相同
这里唯一需要注意的就是,保证每个对象拥有的唯一性
lock(ReentrantLock)与synchronized的不同之处在于,lock更加灵活,lock.trylock()方法,试图获取锁,无论返回的是tru还是false都会执行后来的语句
trylock(time,timetype)
12 volatile
将线程缓冲区的数据立刻刷新到主存中,但是,如果域依赖于它之前的值的话,volatile是无法正常工作的。如果收到其他域影响,也是无法正常工作的。所以优先考虑的应该是synchronized关键字
i++ 和 i+=n 不是原子性的,但在c++中是原子性的,volatile无法改变这一事实。
强调方法间的同步问题...!!!
13 原子类
AtomicInteger AtomicLong AtomicReference
14 gardencount
分析1
我们可以控制建造5个入口,每个入口都可以进人,这五个入口相当于是5个线程
第一,我们需要知道每个线程进入人的情况,进入技术操作与获取操作有并发问题
第二,我们需要知道进入人的总数-----共享计数器,静态成员变量,计数器的增加涉及到并发的问题,计数器的增加和获取也有并发问题
第三,需要一个共享的静态变量来决定是否终止,线程循环也是基于这个条件
这里涉及到的问题,1静态成员变量存储所有对象的引用
2静态方法返回总数
3executor在shutdown之后,等待所有的线程执行结束,这里有一个超时的时间,如果超时时间截止后,还未全部返回的,则为false
class Count{
private int count=0;
public synchronized int increament(){
if(new Random().nextBoolean()) // Yield half the time
Thread.yield();
return count++;
}
public synchronized int getCount(){
return count;
}
}
class Entrance implements Runnable{
private static Count count = new Count();
private static List<Entrance> list = new ArrayList<Entrance>();
private int num=0;
private int id;
private static boolean cancled=false;
public Entrance(int id){
this.id=id;
list.add(this);
}
@Override
public void run() {
// TODO Auto-generated method stub
while(!cancled){
synchronized (this) {
num++;
}
System.out.println(this+"total"+count.increament());
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static Count getCount(){
return count;
}
public String toString(){
return "Entrance " + id + ": " + getNum();
}
public static void cancel(){
cancled=true;
}
public synchronized int getNum(){
return num;
}
public static int getSumCount(){
int sum=0;
for(Entrance entrance:list){
sum+=entrance.getNum();
}
return sum;
}
}
public class GardenCount {
public static void main(String args[]){
ExecutorService es= Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
es.execute(new Entrance(i));
}
es.shutdown();
try {
if(!es.awaitTermination(250, TimeUnit.MILLISECONDS))
System.out.println("Some tasks were not terminated!");
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Entrance.cancel();
System.out.println(Entrance.getCount().getCount());
}
}
15 这里需要对阻塞状态说一下,一个是i/o等待,这个比较常见,计算密集型或者是i/o密集型
一个是wait,wait是卡主,等待notify的命令唤醒
一个是sleep,sleep是线程睡眠,此时操作权交给其它线程执行
一个是锁,A在访问临街资源,B持有临界资源的锁还没释放
16 使用中断,中断阻塞的线程
获取当前线程,执行interrupt方法,中断线程
使用executor的submit方法,提交一个任务为future,通过future的cancel方法,中断当前线程。
这里需要注意:
1普通的sleep是可以中断的,中断后,抛出异常
2读取文件的io型操作,是不可被中断的
3陷入死锁的情况,是不可被中断的
这个地方要特别注意io操作很有可能会造成死锁,特别是针对web上的操作
关闭任务在其上发生阻塞的底层资源,也就是close之后才会引发中断的操作命令
executor的shutdown,是不允许提交任务了,未执行的可以继续执行
executor的shutdownnow,是结束所有的任务,并返回未执行任务列表
需要区别socket和i/o的不同之处,这里面的在executor执行shutdownnow之后,是不会被中断的
在socket.close后会中断并引发异常,而在io.close后不会中断,必须要输入后才会中断...----考虑到nio
17 对于使用synchronized的一个小问题
对于嵌套调用,而且存在锁的情况,这种是不会阻塞的,因为法1持有的锁,在调用f2的时候,f2会尝试获取f1加的锁,这种情况下是允许的。
class Mul{
public synchronized void f1(int count){
if(count-->0){
System.out.println("f1 is calling f2:"+count);
f2(count);
}
}
public synchronized void f2(int count) {
// TODO Auto-generated method stub
if(count-->0){
System.out.println("f2 is calling f1:"+count);
f1(count);
}
}
}
18 lock 和 lockInterruptibly
lockInterruptibly 与 lock比较区别在于
lockInterruptibly 优先考虑响应中断,而不是响应锁定的普通获取或重入获取
class BlockedMutex {
private Lock lock = new ReentrantLock();
public BlockedMutex() {
// Acquire it right away, to demonstrate interruption
// of a task blocked on a ReentrantLock:
lock.lock();
}
public void f() {
try {
// This will never be available to a second task
lock.lockInterruptibly(); // Special call
System.out.println("lock acquired in f()");
} catch(Exception e) {
System.out.println("Interrupted from lock acquisition in f()");
}
}
}
thread.interrupt();对于lock类型的阻塞是没有什么效果的,例如两次使用lock方法。
这里最好的方法是使用lockInterruptibly方法,可以响应中断并抛出异常
19 wait 和 notify
注意的第一是,因为他们涉及到锁的操作,因此必须要放到加锁的函数中或者放到同步代码块中,否则则会抛出异常
sleep和yield不涉及到锁的操作,因此不用。
20scheduleAtFixedRate和schedule
主要的不同在于第一个存在线程同步的问题,当任务执行时间大于间隔时间的出力方式不同
第一个是严格按照时间频率执行,会重新开一个线程执行,而schedule则会按照任务执行的顺序,使用一个线程顺序执行。
(TimerTask task, long delay, long period)
(TimerTask task, Date firsttime, long period)
第一个是任务,第二个是开始时间,第三个是频率
- java编程思想—并发编程小结一
- Java编程思想—并发编程小结二
- Java编程思想读书笔记一:并发
- 《Java 编程思想》学习小结 (一)
- java编程思想笔记-并发之并发锁(一)
- JAVA并发编程小结
- JAVA编程思想——并发
- 《Java编程思想》——并发读书笔记
- Java编程思想笔记—并发1
- 《Java编程思想》学习笔记18——并发编程(一)
- 《Java编程思想》学习笔记18——并发编程(一)
- 《Java编程思想》学习笔记18——并发编程(一)
- Java编程思想-java中的并发(一)
- 并发(java编程思想)笔记
- java编程思想--21 并发
- Java编程思想之并发
- Java编程思想-21并发
- JAVA编程思想笔记--并发
- 字符串中的快速模式匹配1
- 算法导论 2.1-3
- Tomcat下部署多个项目
- (3)Hive 1.2.1 安装部署
- 作用域和生命周期
- java编程思想—并发编程小结一
- 开关电源的使用
- 使用Glide显示圆图圆角图,高斯模糊图等,超简单
- 欢迎使用CSDN-markdown编辑器
- 【LeetCode】Container with Most Water
- Mapper XML配置
- UICollectionView入门--使用系统UICollectionViewFlowLayout布局类
- Java后端书籍推荐2
- leetcode第十周解题总结