Java 线程(一)

阅读更多
复习一下Java的线程 , 看了官网上的教程:http://download.oracle.com/javase/tutorial/essential/concurrency/index.html

对于并发,主要有线程和进程两种实现方式,区别很明显,java可以多进程:
使用ProcessBuilder(java.lang),
ProcessBuilder pb =
   new ProcessBuilder("myCommand", "myArg1", "myArg2");
Map env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
File log = new File("log");
pb.redirectErrorStream(true);
pb.redirectOutput(Redirect.appendTo(log));
Process p = pb.start();
assert pb.redirectInput() == Redirect.PIPE;
assert pb.redirectOutput().file() == log;
assert p.getInputStream().read() == -1;
(没有仔细看,待会儿,仔细看看)

对于Thread, java实现的两种方式:
1. 简单的new 一个, 然后start, 这样每个Thread都要赋予一个task
2. 把task放到一个executor中,交给系统去处理

简单的创建一个Thread,对于task的设置也有两种方式:
1. 继承Thread,然后重载run方法
2. 实现一个Runnable接口, 然后new Thread(runnalbe)的方式

一个Thread的一些操作:
1. sleep, sleep可以挂起一个线程,sleep(time), 挂起一定时间,当然由于OS的原因,time不是肯定能准确实现的, 同时sleep可以被interrupt, 这时会抛出InterruptedException , 所以一般在sleep的时候,都要对这个异常进行处理
比如,catch
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]);
}
同时,Thread提供了interrupt的状态查询方法, Thread.interrupted(),
for (int i = 0; i < inputs.length; i++) {
    heavyCrunch(inputs[i]);
    if (Thread.interrupted()) {
        //We've been interrupted: no more crunching.
        return;
    }
}

2. join, 会挂起当前线程,等待执行join的线程执行结束,返回
如:  在当前线程中使用 t.join(), t为另一个线程, 则当前线程等待t线程执行完毕
同时join会被interrupt, 抛出InterruptedException

同步: 这是在处理并发程序时,必须面对的,主要用于解决两种error
1. Thread Interference :是指在一个线程对一个对象进行一个操作时,另一个线程对当前对象的干扰, 比如: c++ 这个操作,虽然只有一行但是在JVM中会分成几步处理,这就会给其他线程在几步中干涉的机会
2. Memory Consistency Error 是指对于线程间共享的对象,一旦一个线程对其进行改变,对于另一个线程并一定是可见的

解决方法:
1. sychronized method:  对并发的方法声明synchronized, 这样就会在同时只有一个线程使用这个方法,可以有效的避免出现Thread Interference. 同时一个synchronized 的方法结束后,会产生happens-before 的效果,简单说就是操作结果对其他线程可见,避免了error2
注意:
1. constructor method是不能synchronized的, 因为同时对一个对象,只可能有一个线程new
2. final 变量是不能修改的,不需要对操作进行synchronized

2. synchronized statements: 对一些操作把,把他们放在synchronized语句块中,而不是简单的synchronized方法, 需要提供一个synchronized的对象。

synchronized 实现同步的原理, 还是通过锁机制,对于synchronized方法的锁,是由对象提供的,在获取锁后,执行方法,返回时释放锁(甚至在抛出异常时也会释放锁), 这种锁叫做: Intrinsic Lock,  提供了对于对象的单一访问和happens-before两种功能, 而synchronized statement 需要的对象,就是提供锁的对象。
注意: 对于static的方法的锁,是class的锁,而不是对象

对于锁使用的error :
1. deadLock, 常见错误, 简单说就是, 进入一个两个线程都在等待对方释放锁的状态。
具体看理解了。官网例子:
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();
    }
}

2. starvation, 对于一个线程在synchronized的method中处理时间很长,就会造成其他线程j饥饿
3. liveLock , 一个线程是另一个线程的response,同时另一个线程又是其他线程的response,不停的link下去,就会造成liveLock,没碰到过,了解一下概念

wait和notify
Object中的方法wait, notify在多线程中应用,
对于需要等待的情况, 可以用wait将当前线程等待,使用notify可以唤醒,并且通过标志位进行控制。
看个例子就明白了:
    public class Drop {
        //Message sent from producer to consumer.
        private String message;
        //True if consumer should wait for producer to send message, false
        //if producer should wait for consumer to retrieve message.
        private boolean empty = true;

        public synchronized String take() {
            //Wait until message is available.
            while (empty) {
                try {
                    wait();
                } catch (InterruptedException e) {}
            }
            //Toggle status.
            empty = true;
            //Notify producer that status has changed.
            notifyAll();
            return message;
        }

        public synchronized void put(String message) {
            //Wait until message has been retrieved.
            while (!empty) {
                try {
                    wait();
                } catch (InterruptedException e) {}
            }
            //Toggle status.
            empty = false;
            //Store message.
            this.message = message;
            //Notify consumer that status has changed.
            notifyAll();
        }
    }

    import java.util.Random;

    public class Producer implements Runnable {
        private Drop drop;

        public Producer(Drop drop) {
            this.drop = drop;
        }

        public void run() {
            String importantInfo[] = {
                "Mares eat oats",
                "Does eat oats",
                "Little lambs eat ivy",
                "A kid will eat ivy too"
            };
            Random random = new Random();

            for (int i = 0; i < importantInfo.length; i++) {
                drop.put(importantInfo[i]);
                try {
                    Thread.sleep(random.nextInt(5000));
                } catch (InterruptedException e) {}
            }
            drop.put("DONE");
        }
    }

    import java.util.Random;

    public class Consumer implements Runnable {
        private Drop drop;

        public Consumer(Drop drop) {
            this.drop = drop;
        }

        public void run() {
            Random random = new Random();
            for (String message = drop.take(); ! message.equals("DONE");
                    message = drop.take()) {
                System.out.format("MESSAGE RECEIVED: %s%n", message);
                try {
                    Thread.sleep(random.nextInt(5000));
                } catch (InterruptedException e) {}
            }
        }
    }
                   
Immutable Object:
就像final 的变量,可以不用synchronized, 设计成不可变的Object,也可以不需要synchronized。而Immutable需要遵循:
1. 没有setter,
2. 所有字段,final private
3. 不允许子类,override 字段, 最简单 就是 final 类(不允许继承), 或者使用单例模式
4. 如果保护可变对象的引用,不允许她们更改,首先在内部的方法中不改变它们,其次最好不要共享这个对象,创建对象的副本,保存这个副本


你可能感兴趣的:(Java,多线程,thread,Oracle,设计模式)