《java多线程笔记.docx》由会员分享,可在线阅读,更多相关《java多线程笔记.docx(28页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第一章多线程线程与进程的区别1.1. 什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源。而一个进程又是由多个线程所组成的。进程下面至少有一个线程,也可能有多个线程。1-N的关系。进程:可以理解为正在运行中的程序:厘任务告理器文件(F)选项(0)查看(V)-X迸程性能应用历史记录启动用户详细信息服务人56%衍个4中立的软件;云行的前梅就以45%内存0% 逊0%网络ty. 11 JSl JM-Jj rlALoyLAt.I应用AT 午 edipse.exe0%527.1 MB0 MB型0 Mbps 0 G-Live (32 位)14.1%121.8
2、 MB0.1 MB 型0.2 Mbps G Google Chrome (32 位)(10)0%201.3 MB0 MB型0 Mbps KK像机(32位)13.5%97.9 MB0.1 MB型0 Mbps n Windows资源告理器0.2%41.4 MB0 MB型0 Mbps Q WPS Office (32 检0%35.5 MB0 MB型0 Mbps行任务告理器12.5%27.1 MB0.1 MB型0 Mbps后台进程(101) 恒 Alibaba PC Safe Service (32 .0%9.5 MB0 MB型0 Mbps AlilM (32 位)0%2.9 MB0 MB型0 Mbp
3、s 恒 Antimalware Service Executa.0%252.9 MB0 MB型0 Mbps、Apache HTTP Server (32 0%5.0 MB0 MB型0 MbpsV1.2. 什么是线程?什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针、程序计数器等),但代码区是共享的, 即不同的线程可以执行同样的函数。实现Runnable接口完成资源共享:class SellTickets2 implements Runnable /票数private Integer tickets = 10;Overridepublic void run() /定义循
4、环是否继续的标志boolean flag = true;/循环while (flag) /判断if (tickets 0) System. out. print In (Thread. currentThread(). getName() + 售票”+ (tickets-); else flag = false;/ 中断)public class TestThreadRunnable public static void main(String args) /实例化多线程对象SellTickets2 st = new SellTickets2();/借助Thread完成启动线程Thread t
5、 = new Thread(st);t.setName(窗口一”); t.start();/借助Thread完成启动线程Thread t2 = new Thread(st);t2.setName(窗 口二”);t2.start();/借助Thread完成启动线程Thread t3 = new Thread(st); t3.setName(“窗口三”); t3.start();/借助Thread完成启动线程Thread t4 = new Thread(st); t4.setName (窗口四); t4.start();两者的选用总结口可见,实现Runnable接口相对于继承Thread类来说,有
6、如下显著的优势:。(1)、适合多个相同程序代码的线程去处理同一资源的情况。 (2)、可以防止由于Java的单继承特性带来的局限。令(3)、增强了程序的健壮性,代码能够被多个线程共享,代码与数 据是独立的。第四章Callab加和Future创立线程(可以有返回值的线程)(1)创立Callable接口的实现类,并实现call。方法,该call。方法将作为线程执行体,并且有返回值。(2)创立Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对 象的call。方法的返回值。(3)使用FutureTask对象作为Thre
7、ad对象的target创立并启动新线程。(4)调用FutureTask对象的get。方法来获得子线程执行结束后的返回值案例:* 需求:求1+2+3+. . .10。的返回值5050* 1创立测试类* 2定义实现Callable接口的线程类,重写方法call。* 3创立callable的实例对象* 4要使用callable的包装类FutureTask,以便封装返回值* 5借助Thread类完成启动线程* /class MyCallable implements CallableOverridepublic Integer call() throws Exception 定义一个累计的值int s
8、um = 0;循环for(int i = 1;i 101;i+) sum += i;)return sum;)public class TestCallable public static void main(String args) throws InterruptedException, ExecutionException 创立callable的实例对象MyCallable me = new MyCallable();要使用callable的包装类FutureTask,以便封装返回值 FutureTask ft = new FutureTask(mc);借助Thread类完成启动线程Th
9、read t = new Thread(ft);t.start();获取值Integer result = ft.get();/打印计算的值System.out.println(l 累加至ij 100 的值:+ result);)return result;)public class TestCallableMaxNum2 public static void main(String args) throws InterruptedException, ExecutionException 创立多线程对象MyCallable2 mc2 = new MyCallable2(28,5,13);包装
10、类 FutureTaskFutureTask ft = new FutureTask(mc2);借助Thread类 传包进去构造器Thread t = new Thread(ft);启动线程 t.start();获取计算后的值Integer max = ft.get();System.out.printin(max: + max);)第五章创立线程的三种方式的比照(面试题)采用实现Runnable、Callable接口的方式创见多线程时,优势是:1 .线程类只是实现了 Runnable接口或Callable接口,还可以继承其他类。private void init(ThreadGroup g,
11、 Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) 多个线程可以共享同一个target对象this.target = target;).在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从 而可以将CPU、代码和数据分开,形成清晰的模型,较好地表达了面向对象的思想。面向接I编程劣势是:1.编程稍微复杂,如果要访问当前线程,那么必须使用Thread.currentThread。方法。使用继承Thre
12、ad类的方式创立多线程时优势是:3.编写简单,如果需要访问当前线程,那么无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。 劣势是:1.线程类已经继承了 Thread类,所以不能再继承其他父类。第六章线程的常用操作方法线程操作的主要方法No.方法名称类型描述1public Thrcad(Runnable target)构造接收Rabk接口子类对象,实例化Thread对象7 一public Thread(Runnabie target String name)构造接收Rmnable接口子初象,实例化Ttaead对象,并设置线程名称3public Thre
13、ad(Strir name)构造实例化Mad对象,并设置线程名称4public static Thread cunentThread()蕾遇返回目前正在执行的线程5public final String getName()。遇返回线程的名称6public final int getPriorityO普通发挥线程的优先级7public boolean islntempted()普通判断目葩线程是否被中断,如果是,退回tne否那么返回false8puHic final boolean isAlive()判断程是否在活动,如果是,返回true,否那么返回fake9public final void
14、joinQ throws Intcm)1edException普通等待纹程死亡10public final synchronized void join(long millis) throws I nterruptedExcqXion普通萼待millis毫眇后,线程死亡11public void nai)普遇执行线程12pubbc final void etName(String namr)普通设定线程名称13public final void setPrioriint newPriority)普通设定线程的优先值14public static void skep(long millis) t
15、hrows Imem|)tedExcqMion普通使目前正在执行的线程休眠millis毫秒15public void $Urt()普通开始执行线程16public static void yield()普通格目前正在执行的线程暂停,允许其它线程执行17public final void setDaemon(boolean on)普通将一个线程设量或后台运行18public final void setPrioritint newPriority)普通更改统程的优先级6.1.取得和获取线程的名字取得和设置线程名称口在Thread类中,可以通过getName()方法取得线程的名称,通过 setNa
16、me()方法设置线程的名称。口线程的名称一般在启动线程前设置,但也允许为已经运行的线程设置名称。 允许两个Thread对象有相同的名字,但为了清晰,应该尽量防止这种情 况的发生。口另外,如果程序并没有为线程指定名称,那么系统会自动的为线程分配一个 名称。62判断线程是否启动判断线程是否启动口通过Thread类之中的start。方法通知CPU这个线程已经准备好启动,之后 就等待分配CPU资源,运行此线程了。那么如何判断一个线程是否已经启 动了呢?在Java中可以使用isAlive()方法来测试线程是否已经启动而且仍 然在启动。6.3. 线程的强制运行线程的强制运行口在线程操作中,可以使用join
17、。方法让一个线程强制运行,线程强制运行 期间,其他线程无法运行,必须等待此线程完成之后才可以继续执行。class MyRunnable implements RunnableOverridepublic void run() for(int i = 0;i 50;i+) System.out.printIn(Thread.currentThread().getName() + * + i);)public class Test3oin2 public static void main(String args) throws InterruptedException 创立实例MyRunnable
18、 mr = new MyRunnable();借助Thread启动线程Thread t = new Thread(mr,“线程一);t.start();/join/*当t调用join这个方法,当前t线程就会强制执行(阻塞其它的线程)会等待这个t线程一直执行完毕(死亡)为止, 才会执行其它的线程。*/t.join();for(int i = 0;i for(int i = 0;i for(int i = 0;i for(int i = 0;i for(int i = 0;i 锁synchronized (obj) try Thread.steep(100); catch (Interrupted
19、Exception e) e.printStackTrace();判断if(tickets 0) System.out.printin(Thread.currentThread().getName() + + (tickets-); else flag = false;)1.1.2. 同步方法同步方法口除了可以将需要的代码设置成同步代码块之外,也可以使用synchronized 关键字将一个方法声明成同步方法。口同步方法定义格式:令synchronized方法返回值方法名称(参数列表)class SellTicket2 implements Runnable private Integer t
20、ickets = 10;Overridepublic void run() 定义标志boolean flag = true;循环while(flag) flag = sells(flag);同步方法private synchronized boolean sells(boolean flag) try (Thread.sleep(100); catch (InterruptedException e) e.printStackTrace();)判断if(tickets 0) System.out.printIn(Thread.currentThread().getName() + + (tic
21、kets-);else flag = false;)return flag;问:同步方法有锁吗?有锁,是同一个对象。9.2. 静态同步方法中有锁吗?是this吗?有锁。不是this。是class对象,反射的时候会有介绍。9.3. 练习:两个人AB通过一个账户A在柜台取钱和B在ATM机取钱!程序分析:钱的数量要设置成一个静态的变量。两个人要取的同一个对象值两个人AB通过一个账户A在柜台取钱和B在ATM机取钱!程序分析:钱的数量要设置成一个静态的变量。两个人要取的同一个对象值 */public class TestDrawMoney public static void main(String a
22、rgs) /DrawMoney 实例DrawMoney dm = new DrawMoney(200d);借助Thread启动线程Thread tl = new Thread(dm,妈妈);Thread t2 = new Thread(dm,儿尸);Thread t3 = new Thread(dm,女儿);tl.start();t2.start();t3.start(); class DrawMoney implements Runnableprivate double balance = 400;private double money;public DrawMoney(double d)
23、 this.money = d;Overridepublic void run() 判断余额要大于取钱的值要对余额操作synchronized (this) if(balance = money) try Thread.sleep(100); catch (InterruptedException e) e.printStackTrace();balance -= money;System. out. print In (Thread. currentThread(). getName() + 取钱+ money + ”,余额为:+ balance); else System. out. pr
24、int In (余额缺乏);调用Collections.synchronizedXxx()返回线程平安的集合 static Collection9.4. 线程平安的集合synchronizedCollection(Collection c) 返回由指定集合支持的同步(线程平安)集合。static ListsynchronizedList(List list)返回由指定列表支持的同步(线程平安)列表。static MapsynchronizedMap (Map m)返回由指定地图支持的同步Q策平安)映射。static NavigableMapsynchronizedNaviged)leMap (
25、NavigableMap m)返回由指定的可导航地图支持的同步(线程平安)可导航地图。static NavigableSetsynchronizedNavigableSet(NavigaleSet s)返回由指定的可导航集支持的同步(线程平安)可导航集。static SetsynchronizedSet(Set s)返回由指定集合支持的同步3好呈平安)集。static SortedMapcK,VsynchronizedSortedMap(SortedMapCK,V m)返回由指定的排序映射支持的同步(线程平安)排序映射。static SortedSetsynchronizedSortedSet
26、(SortedSet s)返回由指定的排序集支持的同步(线程平安)排序集。第十章Lock接口synchronized叫悲观锁,这个锁会天生会认为一定会有别的线程跟我抢这个锁,也叫重豉级锁,适用范围活跃的网 站。Lock叫乐观锁,也叫轻量级锁,也有叫法称为自旋锁。有的时候,synchronized关键字会显得过于沉重:,不够灵活。synchronized方法或语句的使用提供了对与每个对 象相关的隐式监视器锁的访问,但却强制所有锁获取和释放均要出现在个块结构中:当获取了多个锁时,它们必 须以相反的顺序释放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。这个时候Lock出现。Lock不是Jav
27、a中的关键字而是包中的一个接I。下面我们简单介绍一下Lock接I。Lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有 差异很大的属性,可以支持多个相关的Condition对象。Lock相对于synchronized关键字而言更加灵活,你可以臼由得选择我你想要加锁的地方。当然更高的自由度也带来 更多的责任。public interface LockLock实现提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差异很大的属性,可以支持多个相关的 Condition 对象。锁是控制
28、多个线程对共享资源进行访问的工具。通常,锁提供了对共享资源的独占访问。一次只能有一个线程获得锁,对共享资源的所有访问都需要首先 获得锁。不过,某些锁可能允许对共享资源并发访问,如ReadTriteLock的读取锁。synchronized方法或语句的使用提供了对与每个对象相关的陵式监视器锁的访问,但却强制所有锁获取和杼放均要出现在一个块结构中:当获取了多个领 时,它们必须以相反的顺序锋放,且必须在与所有锁被获取时相同的词法范围内释放所有锁。虽然synchronized方法和语句的范国机制使得使用监视器锁编程方便了很多,而且还帮助防止了很多涉及到锁的常见编程楮误,但有时也需要以更为灵活 的方式使
29、用锁。例如,某些遍历并发访问的数据结果的算法要求使用hand-over-hand或chain locking:获取节点A的锁,然后再获取节点B的 锁,然后释放A并获取C,然后驿放B并获取D,依此类推。Lock接口的实现允许锁在不同的作用范围内获取和驿放,并允许以任何顺序获取和释放多 个锁,从而支持使用这种技术.随着灵活性的增加,也带来了更多的责任。不使用块结构锁就失去了使用synchronized方法和语句时会出现的锁自动释放功能.在大多数情况下,应该使 用以下语句: 锁定和取消锁定出现在不同作用范围中时,必须谨慎地确保保持锁定时所执行的所有代码用try-finally或try-catch加以
30、保护,以确保在必要时程放 锁。Lock实现提供了使用synchronized方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试()、一个获取可中断锁的尝试 (lockinterruptibly()和一个获取超时失效锁的尝试(tryLock(lon% TisUnit)。Lock类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测.如果某个实现提供了这样特殊的语义,那么该实现必须对 这些语义加以记录.注意,Lock实例只是普通的对象,其本身可以在synchronized语句中作为目标使用.获取Lock实例的监视器锁与调用该实例的任何lockH方法没有特 别的
31、关系。为了防止混淆,建议除了在其自身的实现中之外,决不要以这种方式使用Lock实例。除非另有说明,否那么为任何参数传递null值都将导致抛出ullPointerException。volatile关键字/ Method Java/bng/Object.,*:OV0: aload.O1: Invokespecial #14: aload_0S: bipush 8/ Method Java/lang/Object.* :0V这时候有个线程去访问t.m - 0还有月夕程去/河t.m图5传值8) -8class TInt m = 8:)T t = new TQ:保证内存的可见性第十一章死锁ILL概念同
32、步锁使用的弊端,当线程任务中出现了多个同步时,如果同步中嵌套了其他同步。这时容易引发一种想象:程序 无限等待,这样的现象称为死锁。这种情况能防止就尽量防止。死锁口同步可以保证资源共享操作的正确性,但是过多同步也会产生问题。例如: 现在有张三想要李四的画,李死想要张三的书,那么张三对李四说了:“把你的画给我,我就给你书”,李四也对张三说了: “把你的书给我, 我就给你画”,此时,张三在等着李四的答复,而李四也在等着张三的答 复,那么这样下去最终结果可想而知,张三得不到李四的画,李四也得不 到张三的书,这实际上就是死锁的概念。public class TestStringDeakLock2 pub
33、lic static void main(String args) /定义2个StringBuffer对象 StringBuffer si = new StringBuffer();StringBuffer s2 = new StringBuffer();/ 2定义2个线程类并启动线程 new Thread(new Runnable() 0Overridepublic void run() /获得si的锁 synchronized (si) sl.append(a);s2.append(l);try Thread.seep(100); catch (InterruptedException e
34、) e.printStackTrace();)/嵌套锁synchronized (s2) sl.appendCb);s2.append(2);/System.out.println(sl);/System.out.printIn(s2); ),start();/ 2定义2个线程类并启动线程 new Thread(new Runnable() 0Override public void run() /获得si的锁 synchronized (s2) sl.append(c);s2.append(3);try Thread.steep(100); catch (InterruptedException e) e.printStackTrace();/嵌套锁synchroni