《JavaJDK6学习笔记第15章.ppt》由会员分享,可在线阅读,更多相关《JavaJDK6学习笔记第15章.ppt(47页珍藏版)》请在金锄头文库上搜索。
1、第15章线程线程线程入门同步化议题concurrent套件新增类别继承Thread继承java.lang.Thread类别,并重新定义run()方法实例化您自定义的Thread类别使用start()方法启动线程继承Threadpublic class EraserThreadextends Thread private boolean active; private String mask; /重新定义run()方法 public void run () while(isActive() System.out.print(mask); try /暂停目前的线程50毫秒Thread.curren
2、tThread().sleep(50); catch(InterruptedException e) e.printStackTrace(); 继承Thread /启动Eraser线程 EraserThread eraserThread = new EraserThread(#); eraserThread.start(); String password = scanner.next(); eraserThread.setActive(false);在Java SE 6中可以使用System.console()来取得java.io.Console物件使用Console物件的readPassw
3、ord()方法,就可以避免输入的密码被窥视的问题实作Runnable界面如果您的类别已经要继承某个类别,那么您就不能继承Thread类别继承了Thread类别,您就不能再继承其它类别实作java.lang.Runnable接口来定义具线程功能的类别Runnable接口中定义一个run()方法要实作在实例化一个Thread对象时,可以传入一个实作Runnable接口的对象作为自变量实作Runnable界面public class EraserimplementsRunnable /实作Runnable private boolean active; private String mask; /重
4、新定义run()方法 public void run () while(isActive() System.out.print(mask); try /暂停目前的线程50毫秒Thread.currentThread().sleep(50); catch(InterruptedException e) e.printStackTrace(); 实作Runnable界面 /Eraser实作Runnable界面 Eraser eraser = new Eraser(#); /启动Eraser线程 Thread eraserThread = new Thread(eraser); eraserThre
5、ad.start(); String password = scanner.next(); eraser.setActive(false);Daemon线程一个Daemon线程是一个在背景执行服务的线程如果所有的非Daemon的线程都结束了,则Daemon线程自动就会终止从Main方法开始的是一个非Daemon线程如果希望某个线程在产生它的线程结束后跟着终止,要将它设为Daemon线程Daemon线程 Thread thread = new Thread( /这是匿名类别的写法 new Runnable() public void run() while(true) System.out.pr
6、int(T); ); /设定为Daemon线程 thread.setDaemon(true); thread.start();使用setDaemon()方法来设定一个线程是否为Daemon线程预设所有从Daemon线程产生的线程也是Daemon线程线程生命周期执行start()之后,线程进入Runnable状态,此时线程尚未真正开始执行必须等待排班器(Scheduler)的排班线程生命周期线程有其优先权,由1(Thread.MIN_PRIORITY)到10(Thread.MAX_PRIORITY)优先权越高,排班器越优先排入执行,如果优先权相同,则输流执行(Round-robin方式)线程生命
7、周期如果您想要让目前线程礼让一下其它线程,让它们有机会取得执行权,您可以呼叫绪行绪的yield()方法 / . Thread thread = new Thread(new Runnable() public void run() / . while(true) / . yield(); /暂时让出执行权 ); thread.start(); / .线程生命周期有几种状况会让线程进入Blocked状态等待输入输出完成呼叫sleep()方法尝试取得对象锁定呼叫wait()方法线程生命周期进入Blocked状态,以下的几个对应情况让线程回到Runnable状态输入输出完成呼叫interrupt()
8、取得对象锁定呼叫notify()或notifyAll()线程生命周期 Thread thread = new Thread(new Runnable() public void run() try /暂停99999毫秒 Thread.sleep(99999); catch(InterruptedException e) System.out.println(Im interrupted!); ); thread.start(); thread.interrupt(); / interrupt it right now线程的加入(join)当线程使用join()加入至另一个线程时,另一个线程会等
9、待这个被加入的线程工作完毕,然后再继续它的动作join()的意思表示将线程加入成为另一个线程的流程之一线程的加入(join) Thread threadB = new Thread(new Runnable() public void run() try catch(InterruptedException e) e.printStackTrace(); ); threadB.start(); try / Thread B加入Thread A threadB.join(); catch(InterruptedException e) e.printStackTrace(); 线程的停止不建议使
10、用stop()来停止一个线程的运行public class SomeThread implements Runnable private boolean isContinue = true; public void terminate() isContinue = false; public void run() while(isContinue) / . some statements 线程的停止不建议使用stop()来停止一个线程的运行Thread thread = new Thread(new SomeThread();thread.start();thread.interrupt();
11、ThreadGroup每一个线程产生时,都会被归入某个线程群组如果没有指定,则归入产生该子线程的线程群组中可以自行指定线程群组,线程一但归入某个群组,就无法更换群组ThreadGroupjava.lang.ThreadGroup类别正如其名,可以统一管理整个群组中的线程ThreadGroup中的某些方法,可以对所有的线程产生作用interrupt()方法可以interrupt群组中所有的线程setMaxPriority()方法可以设定群组中线程所能拥有的最大优先权ThreadGroup threadGroup1 = new ThreadGroup(group1);ThreadGroup thr
12、eadGroup2 = new ThreadGroup(group2);Thread thread1 = new Thread(threadGroup1, group1s member);Thread thread2 = new Thread(threadGroup2, group2s member);ThreadGroup想要一次取得群组中所有的线程来进行某种操作,可以使用enumerate()方法Thread threads = new ThreadthreadGroup1.activeCount();threadGroup1.enumerate(threads);ThreadGroupu
13、ncaughtException()方法是当群组中某个线程发生非受检例外(Uncheckedexception)时,由执行环境呼叫进行处理 ThreadGroup threadGroup1 = /这是匿名类别写法 new ThreadGroup(group1) /继承ThreadGroup并重新定义以下方法 /在线程成员丢出unchecked exception /会执行此方法 public void uncaughtException(Thread t, Throwable e) System.out.println(t.getName() + : + e.getMessage(); ;Un
14、caughtExceptionHandler可以让您的例外处理类别实作Thread.UncaughtExceptionHandler界面,并实现其uncaughtException()方法public class ThreadExceptionHandler implements Thread.UncaughtExceptionHandler public void uncaughtException(Thread t, Throwable e) System.out.println(t.getName() + : + e.getMessage(); thread1.setUncaughtEx
15、ceptionHandler(handler);同步化如果一个对象所持有的数据可以被多线程同时共享存取时,您必须考虑到数据同步的问题数据同步指的是两份数据整体性、一致性同步化同步化数据的不同步而可能引发的错误通常不易察觉可能是在您程序执行了几千几万次之后,才会发生错误这通常会发生在您的产品已经上线之后,甚至是程序已经执行了几年之后同步化 public void setNameAndID(String name, String id) this.name = name; this.id = id; if(!checkNameAndIDEqual() System.out.println(coun
16、t + ) illegal name or ID.); count+; 同步化使用synchronized关键词publicsynchronized void setNameAndID(String name, String id) this.name = name; this.id = id; if(!checkNameAndIDEqual() System.out.println(count + ) illegal name or ID.); count+;同步化物件的锁定(lock)观念同步化使用synchronized关键词public void setNameAndID(String
17、 name, String id) synchronized(this) this.name = name; this.id = id; if(!checkNameAndIDEqual() System.out.println(count + ) illegal name or ID.); count+; /arraylist参考至一个ArrayList的一个实例synchronized(arraylist) arraylist.add(new SomeClass();同步化同步化确保数据的同步,但所牺性的就是在于一个线程取得对象锁定而占据同步化区块,而其它线程等待它释放锁定时的延迟wait(
18、)、notify()wait()、notify()与notifyAll()是由Object类别所提供的方法宣告為final在同步化的方法或区块中呼叫wait()方法当物件的wait()方法被调用,目前的线程会被放入对象的等待池中,线程归还对象的锁定其它的线程可竞争对象的锁定wait()、notify()wait()、notify()当物件的notify()被调用,它会从目前对象的等待池中通知一个线程加入回到锁定池的Blocked状态被通知的线程是随机的,被通知的线程会与其它线程共同竞争对象的锁定如果您呼叫notifyAll(),则所有在等待池中的线程都会被通知回到锁定池的Blocked状态wa
19、it()、notify()当线程呼叫到对象的wait()方法时,表示它要先让出对象的锁定并等待通知,或是等待一段指定的时间被通知或时间到时再与其它线程竞争对象的锁定如果取得锁定了,就从等待点开始执行wait()、notify() public synchronized void setProduct(int product) if(this.product != -1) try /目前店员没有空间收产品,请稍候! wait(); catch(InterruptedException e) e.printStackTrace(); this.product = product; System.o
20、ut.printf(生产者设定(%d)%n, this.product); /通知等待区中的一个消费者可以继续工作了 notify(); wait()、notify() public synchronized int getProduct() if(this.product = -1) try /缺货了,请稍候! wait(); catch(InterruptedException e) e.printStackTrace(); int p = this.product; System.out.printf(消费者取走(%d)%n, this.product); this.product =
21、-1; /取走产品,-1表示目前店员手上无产品 /通知等待区中的一个生产者可以继续工作了 notify(); return p; 容器类的线程安全可以使用java.util.Collections的synchronizedXXX()等方法来传回一个同步化的容器对象使用Iterator遍访对象时,您仍必须实作同步化List list = Collections.synchronizedList(new ArrayList(); List list = Collections.synchronizedList(new ArrayList(); . synchronized(list) Iterat
22、or i = list.iterator(); while (i.hasNext() foo(i.next(); ThreadLocal类别尝试从另一个角度来思考多线程共享资源的问题共享资源这么困难,那么就干脆不要共享使用java.lang.ThreadLocal,为每个线程创造一个资源的复本ThreadLocal类别 public T get() /取得目前执行get()方法的线程 Thread current = Thread.currentThread(); /根据线程取得线程自有的资源 T t = storage.get(current); /如果还没有线程专用的资源空间 /则建立一个
23、新的空间 if(t = null & !storage.containsKey(current) t = initialValue(); storage.put(current, t); return t; public void set(T t) storage.put(Thread.currentThread(), t); ThreadLocal类别 public static SomeResource getResource() /根据目前线程取得专属资源 SomeResource resource = threadLocal.get(); /如果没有取得目前专属资源 if(resour
24、ce = null) /建立一个新的资源并存入ThreadLocal中 resource = new SomeResource(); threadLocal.set(resource); return resource; BlockingQueue如果BlockingQueue的内容为空,而有个线程试图从Queue中取出元素,则该线程会被Block,直到Queue有元素时才解除Block如果BlockingQueue满了,而有个线程试图再把资料填入Queue中,则该线程会被Block,直到Queue中有元素被取走后解除BlockBlockingQueue方法说明add()加入元素,如果队列是满
25、的,则丢出IllegalStateExceptionremove()传回并从队列移除元素,如果队列是空的,则丢出NoSuchElementExceptionelement()传回元素,如果队列是空的,则丢出NoSuchElementExceptionoffer()加入元素并传回true,如果队列是满的,则传回falsepoll()传回并从队列移除元素,如果队列是空的,则传回nullpeek()传回元素,如果队列是空的,则传回nullput()加入元素,如果队列是满,就blocktake()传回并移除元素,如果队列是空的,就blockBlockingQueueArrayBlockingQueue指定容量大小来建构LinkedBlockingQueue默认没有容量上限,但也可以指定容量上限PriorityBlockingQueue严格来说不是Queue,因为它是根据优先权(Priority)来移除元素Callable与Future可以协助您完成Future模式http:/ newFixedThreadPool()包括固定数量的线程newSingleThreadExecutor()只有一个线程,循序的执行指定给它的每个任务newScheduledThreadPool()可排程的线程newSingleThreadScheduledExecutor()单一可排程的线程