Java 多线程

来源:互联网 发布:发货找物流软件 编辑:程序博客网 时间:2024/05/18 10:14

Java 多线程

Runnable

当从Runnable中导出一个类时,必须具有run方法。但是这个方法并不存在线程能力。需要将Runnable任务附着到线程上。 
将Runnable对象转变为工作任务的传统方式是把它提交给一个Thread构造器。

Interface : java.lang.RunnableThe Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments called run. This interface is designed to provide a common protocol for objects that wish to execute code while they are active. Class : java.lang.Thread.Thread(Runnable target)Allocates a new Thread object. This constructor has the same effect as Thread (null, target, gname), where gname is a newly generated name. Automatically generated names are of the form "Thread-"+n, where n is an integer.

eg:

public class LiftOff implements Runnable{       protected int countDown = 10;    private static int taskCount =0 ;    private final int id = taskCount ++;    public LiftOff() {}    public String status() {        return "#"+Thread.currentThread().getName() +"#"+                 id + "("+ (countDown>0 ? countDown : "LiftOff") + ")";    }    @Override    public void run() {        while(countDown -- >0){            System.out.println(status());        }    }}

执行

    //直接执行run 并不会启动新线程,在main线程中执行    LiftOff lf1 = new LiftOff();    lf1.run();    //启动子线程Thread-0    LiftOff lf = new LiftOff();         Thread td = new Thread(lf);    td.start();

Executor

java.util.concurrent包中的执行器(Executor)将为你管理Thread对象,从而简化了并发编程。Executor在客户端和任务执行之间提供了一个间接层。Executor允许管理异步任务的执行,而无需显式的管理线程的生命周期。 java.util.concurrent.Executors

Factory and utility methods for Executor, ExecutorService, ScheduledExecutorService,ThreadFactory, and Callable classes defined in this package. 

其中,newCachedThreadPool为每个任务都创建一个线程。newFixedThreadPool使用了有限的线程集来执行所提交的任务。newSingleThreadExecutor在线程中排队执行多个任务。shutdown()防止其他任务提交到当前的Executor

    ExecutorService exec = Executors.newCachedThreadPool();//      ExecutorService exec = Executors.newFixedThreadPool(5);//      ExecutorService exec = Executors.newSingleThreadExecutor();    for(int i=0; i<2; i++){        exec.execute(new LiftOff());    }    exec.shutdown();

同步

加锁

如果你正在写一个变量,它可能接下来将被另一个线程读取,或者正在读取一个上一次已经被另一个线程写过的变量,那么必须使用同步。并且读写线程都必须使用相同的监视器锁同步。

//在方法上加锁public synchronized void f()  {    Pairs q = new Pairs();    p.storeTo(q);    Thread.yield();}//在共用变量上加锁public void g() {    Pairs q = new Pairs();    synchronized(p) {        p.storeTo(q);    }}//在调用对象上加锁public void m() {    Pairs q = new Pairs();    synchronized(this) {        p.storeTo(q);    }}//使用显式加锁private Lock lock = new ReentrantLock();public void n() {    Pairs q = new Pairs();    try {        lock.lock();        p.storeTo(q);    } finally{        lock.unlock();    }}

线程本地存储

线程本地存储是一种自动化机制,可以为使用相同变量的每个不同的线程都创建不同的存储。   
创建和管理线程本地存储可以使用java.lang.ThreadLocal类来实现。   
ThreadLocal不是用来解决共享,竞争等多线程问题,而是提供了保持对象的方法和避免参数传递的方便的对象访问方式。   
 
1,每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。   
 
2,将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。  

协作

wait

wait()会在等待外部产生变化的时候将任务挂起,并且只有在notify()或者notifyAll()发生时,这个任务才被唤醒。 
1,在wait期间对象是释放的,可以通过notify()、notifyAll(),或者时间到期恢复。 
2,sleep()和yield()期间对象仍然是锁定的。

//资源 public class Resource {    private final int ordernum;    public Resource(int ordernum) {this.ordernum = ordernum;}    public String toString() {return "R#" + ordernum;}}//生产者public class Producer implements Runnable{    private Scene rest;    private int count = 0;    public Producer(Scene rest) {this.rest = rest;}    public void run() {        try{            while(!Thread.interrupted()) {                synchronized(this) {                    while( rest.res != null) {                        wait();                    }                    if (++count == 10) {                        System.out.println("Out of food");                        rest.exec.shutdownNow();                    }                    System.out.println("Order up");                    synchronized(rest.customer) {                        rest.res = new Resource(count);                        rest.customer.notifyAll();                    }                    TimeUnit.MILLISECONDS.sleep(100);                }            }        } catch (InterruptedException e) {            e.printStackTrace();        }    }}//消费者public class Consumer implements Runnable {    private Scene rest;    public Consumer(Scene rest){this.rest = rest;}    public void run() {        try {            while(!Thread.interrupted()) {                synchronized(this) {                    while(rest.res == null ){                        wait();                    }                }                System.out.println("Waitperson get" + rest.res);                synchronized(rest.producer) {                    rest.res = null;                    rest.producer.notifyAll();                }            }        } catch (InterruptedException e) {            e.printStackTrace();        }    }}//执行场景public class Scene {    public Resource res;    public Producer producer = new Producer(this);    public Consumer customer = new Consumer(this);    ExecutorService exec = Executors.newCachedThreadPool();    public Scene() {        exec.execute(producer);        exec.execute(customer);    }    public static void main(String[] argv) {        new Scene();    }}

队列

同步队列在任何时刻都只允许一个任务插入或者移除元素。在java.util.concurrent.BlockingQueue接口中提供了这个队列。通常可以使用LinkedBlockingQueue无界队列,或者ArrayBlockingQueue有固定尺寸的队列。 
如果消费者试图从队列中获取对象,而对象为空,那么这些队列还可以挂起消费者任务,并且当有更多元素可用时恢复。阻塞队列可以解决非常大量的问题,简单并且可靠。 
如下例子使用LinkedBlockQueue,一个制作Toast,一个涂抹黄油,一个涂果酱,最后吃掉。

public class Toast {    public enum Status {DRY,BUTTERED,JAMMED};    private final int id;    private Status status = Status.DRY;    public Toast(int id) {this.id = id;System.out.println("Dry made");}    public void butter() { status = Status.BUTTERED;System.out.println("buttered");}    public void jam() {status = Status.JAMMED;System.out.println("jammed");}    public int getId() { return id;}    public Status getStatus() { return status;}    public String toString() { return "T#" + id + ":" + status;}}public class Toaster implements Runnable {    private ToastQueue queue;    private int count;    private Random rand = new Random(45);    public Toaster(ToastQueue queue) {this.queue = queue;}    @Override    public void run() {        try {            while(!Thread.interrupted()) {                TimeUnit.MILLISECONDS.sleep(100+rand.nextInt(500));                Toast t = new Toast(count++);                queue.put(t);            }        } catch(Exception e) {            System.out.println("Toasted ");        }    }}public class Jammer implements Runnable{    private ToastQueue ends;    private ToastQueue buttered;    public Jammer(ToastQueue buttered,ToastQueue ends) {        this.ends = ends;        this.buttered = buttered;    }    @Override    public void run() {        try {            while(!Thread.interrupted()) {                TimeUnit.MILLISECONDS.sleep(500);                Toast t = buttered.take();                t.jam();                ends.put(t);            }        } catch(Exception e) {        }    }}public class Eater implements Runnable{    private ToastQueue ends;    private int counter = 0;    public Eater(ToastQueue ends) {        this.ends = ends;    }    @Override    public void run() {        try {            while(!Thread.interrupted()) {                TimeUnit.MILLISECONDS.sleep(100);                Toast t = ends.take();                if (t.getId() != counter++ || t.getStatus()!= Toast.Status.JAMMED){                    System.out.println("Error");                }            }        } catch(Exception e) {        }    }}public class SceneTest {    public static void main(String[] str) throws Exception{        ToastQueue dry = new ToastQueue();        ToastQueue buf = new ToastQueue();        ToastQueue ends = new ToastQueue();        ExecutorService exec = Executors.newCachedThreadPool();        exec.execute(new Toaster(dry));        exec.execute(new Butter(dry,buf));        exec.execute(new Jammer(buf,ends));        exec.execute(new Eater(ends));        TimeUnit.SECONDS.sleep(5);        exec.shutdownNow();    }}
0 0
原创粉丝点击