Java 多线程

29 篇文章 0 订阅

Java 多线程

Runnable

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

Interface : java.lang.Runnable

The 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值