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(); }}
- 【Java多线程】多线程死锁
- Java 多线程
- java 多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA多线程
- java多线程
- JAVA 多线程
- Java多线程
- java多线程
- JAVA 多线程
- Java 多线程
- Java 多线程
- java多线程
- Java 多线程
- Java多线程
- java 多线程
- spring security 3 实践
- OC -- NSCalendar日历类
- rxrxSerial错误记录
- 矩阵走法问题
- Guest OS, Qemu, KVM工作流程
- Java 多线程
- cocos2d-x笔记(十一)Lua开发飞机大战-5-让飞机动起来
- JavaScript事件冒泡
- 直方图可视化,图像阈值化
- CTreeCtrl 控件的用法
- 实体完整性约束 参照完整性约束 左外连接 右外连接 关系表达式的优化 SQL
- 系统开机引导
- Raw-OS源码分析之系统tick中断
- portlet的开发介绍