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)
第一个是任务,第二个是开始时间,第三个是频率

0 0
原创粉丝点击