标签:
---恢复内容开始---
1、多线程
进程:是一个正在执行中的程序。
每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫控制单元。
线程:就是进程中的一个独立的控制单元
线程在控制着进程的执行
一个进程中至少有一个线程。
Java VM 启动的时候回有一个进程java.exe
该进程中至少一个线程负责java程序的执行
而且这个线程运行的代码存在于main方法中
该线程称之为主线程。
扩展:其实更细节说明jvm,启动的还有垃圾回收机制的线程
创建线程的方式
1.1继承Thread
(1)定义类,继承Thread
(2)覆写Thread类中的run方法
目的:将自定义的代码存储在run方法中,让线程运行。
(3)调用线程的start方法,
作用:启动线程,调用run方法.
多线程的随机性:每次运行结果不同,单核CPU在某一个时刻只能执行一个程序,cpu在快速切换,以达到看上去同时运行的效果。
1.1.1为何覆盖run方法?
Thread用于描述线程,该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。
即run用于存储线程要运行的代码。
1 class Demo extends Thread{ 2 public void run(){ 3 for(int x=0;x<60;x++) 4 { 5 System.out.println("demo run---"+x); 6 } 7 }; 8 } 9 public class ThreadDemo { 10 public static void main(String[] args) { 11 Demo d=new Demo(); 12 //d.start();//开启线程并执行该线程的run方法,demorun与helloworld相互执行 13 d.run();//仅仅是对象调用方法,而线程创建了,并没有运行,demorun全部执行完才执行helloworld 14 for(int x=0;x<60;x++) 15 { 16 System.out.println("Helloworld---"+x); 17 } 18 } 19 }
1.1.2、线程方法
static Thread currentThread();获取当前线程对象,静态的,调用时为Thread.currentThread();
getName();获取线程名称
设置线程名称:setName();或者构造函数
1.2、创建线程的第二种方法(常用)
(1)定义类实现Runnable接口
(2)覆盖Runnable接口中的run方法
将线程要运行的代码存放在该run方法中
(3)通过Thread类建立线程对象
(4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
为何将Runnable接口的子类对象传递
因为自定义的run方法所述的对象是Runnable接口的子类对象
所以要让线程去执行指定对象的run方法,就必须明确该run所属对象
(5)调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
好处:避免单继承的局限性
区别:
继承Runnable:线程代码存放在Thread子类的run方法中,无父类时用
实现Runnable:线程代码存在接口的子类的run方法中,避免局限
1 /* 2 * 需求: 3 * 银行有一个金库 4 * 有两个储户分别存300元,每次存100,分3次 5 * 6 * 目的:该程序是否有安全问题,如果有,如何解决? 7 * 8 * 如何找问题 9 * 1、明确哪些代码是多线程运行代码 10 * 2、明确共享数据 11 * 3、明确多线程运行代码中哪些语句是操作共享数据的 12 * */ 13 14 package learn; 15 class Bank 16 { 17 private int sum; 18 public void add(int n) 19 { 20 sum=sum+n; 21 try{Thread.sleep(10);}catch(Exception e){} 22 System.out.println("sum"+sum); 23 } 24 } 25 class Cus implements Runnable 26 { 27 private Bank b=new Bank(); 28 public void run() 29 { 30 for(int x=0;x<3;x++) 31 { 32 b.add(100); 33 } 34 } 35 } 36 public class BankDemo { 37 public static void main(String[] args) { 38 Cus c=new Cus(); 39 Thread t1=new Thread(c); 40 Thread t2=new Thread(c); 41 t1.start(); 42 t2.start(); 43 } 44 }
1.3、安全问题
当多条语句操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
另一个线程参与执行,导致共享数据的错误
解决办法:
对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中其他线程不可参与执行
同步代码块。
synchronized(对象)
{
需要被同步的代码
}
例:火车上的厕所
同步的前提:
(1)必须有两个或以上的线程
(2)必须多个线程使用同一个锁
PS:必须保证同步中只有一个线程在执行
好处:解决了多线程的安全问题
弊端:判断锁,消耗资源
同步的方式:
(1)同步代码块,使用的锁是obj
(2)同步函数(作修饰符加入),使用的锁是this
(3)静态方法用过的锁是class,即该方法所在类的字节码文件对象,函数列表中写作(类名.class)
1.4、单例
1 package learn; 2 /* 3 * class Single 4 * { 5 * private static final Single s=new Single(); 6 * private Single(){}; 7 * public static Single getInstance() 8 * { 9 * return s; 10 * } 11 * } 12 * */延迟加载的单例模式示例 13 class Single 14 { 15 private static Single s=null; 16 private Single(){} 17 public static Single getInstance(){ 18 if(s==null) 19 synchronized(Single.class){ 20 if(s==null) 21 s=new Single(); 22 } 23 return s; 24 } 25 } 26 public class SingleDemo { 27 28 }
1.5、死锁
同步中嵌套同步
1 package learn; 2 class Test implements Runnable 3 { 4 private boolean flag; 5 Test(boolean flag) 6 { 7 this.flag=flag; 8 } 9 public void run(){ 10 if(flag) 11 { 12 synchronized(MyLock.locka) 13 { 14 System.out.println("if locka "); 15 synchronized(MyLock.lockb) 16 { 17 System.out.println("if lockb"); 18 } 19 } 20 } 21 else 22 { 23 synchronized(MyLock.lockb) 24 { 25 System.out.println("else lockb"); 26 synchronized(MyLock.locka) 27 { 28 System.out.println("else locka"); 29 } 30 } 31 } 32 } 33 } 34 35 class MyLock{ 36 static Object locka=new Object(); 37 static Object lockb=new Object(); 38 } 39 public class DeadLockTicket { 40 public static void main(String[] args) { 41 Thread t1=new Thread(new Test(true)); 42 Thread t2=new Thread(new Test(false)); 43 t1.start(); 44 t2.start(); 45 } 46 }
1.6、线程间通信
1.6.1等待唤醒机制
wait都存放在线程池,notify通常唤醒第一个被等待的,notifyall唤醒全部,三者都必须用在同步中(因须有锁),也需加前缀obj.wait
只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒
而锁是任意对象,所以可以被任意对象调用的方法定义在object类中
1 package learn; 2 class Res{ 3 private String name; 4 private String sex; 5 private boolean flag=false; 6 public synchronized void set(String name,String sex) 7 { 8 if(flag) 9 try{this.wait();}catch(Exception e){} 10 this.name=name; 11 this.sex=sex; 12 flag=true; 13 this.notify(); 14 } 15 public synchronized void out() 16 { 17 if(!flag) 18 try{this.wait();}catch(Exception e){} 19 System.out.println(name+"..."+sex); 20 flag=false; 21 this.notify(); 22 } 23 } 24 25 class Input implements Runnable{ 26 private Res r; 27 Input(Res r) 28 { 29 this.r=r; 30 } 31 public void run() 32 { 33 int x=0; 34 while(true) 35 { 36 if(x==0) 37 r.set("mike", "nan"); 38 else 39 r.set("lili", "nv"); 40 x=(x+1)%2; 41 } 42 } 43 44 } 45 46 class Output implements Runnable{ 47 private Res r; 48 Output(Res r) 49 { 50 this.r=r; 51 } 52 public void run() 53 { 54 int x=0; 55 while(true) 56 { 57 r.out(); 58 } 59 } 60 } 61 public class InputOutputDemo { 62 public static void main(String[] args) { 63 Res r=new Res(); 64 //匿名对象 65 new Thread(new Input(r)).start(); 66 new Thread(new Output(r)).start(); 67 68 // Input in=new Input(r); 69 // Output out =new Output(r); 70 // Thread t1=new Thread(in); 71 // Thread t2=new Thread(out); 72 // t1.start(); 73 // t2.start(); 74 } 75 }
1.6.2、生产者消费者例子
多个生产者,多个消费者,while循环判断标记,notifyAll
1 package pack; 2 class Resource{ 3 private String name; 4 private int count=1; 5 private boolean flag=false; 6 7 public synchronized void set(String name) 8 { 9 while(flag) 10 try{wait();}catch(Exception e){} 11 this.name=name+"..."+count++; 12 System.out.println(Thread.currentThread().getName()+"生产者"+this.name); 13 flag=true; 14 this.notifyAll(); 15 } 16 public synchronized void out(){ 17 while(!flag) 18 try{wait();}catch(Exception e){} 19 System.out.println(Thread.currentThread().getName()+"消费者............"+this.name); 20 flag=false; 21 this.notifyAll(); 22 } 23 } 24 25 class Producer implements Runnable{ 26 private Resource res; 27 Producer(Resource res){ 28 this.res=res; 29 } 30 public void run(){ 31 while(true) 32 { 33 res.set("+商品+"); 34 } 35 } 36 } 37 38 class Consumer implements Runnable{ 39 private Resource res; 40 Consumer(Resource res){ 41 this.res=res; 42 } 43 public void run(){ 44 while(true) 45 { 46 res.out(); 47 } 48 } 49 } 50 public class ProduceConsumerDemo { 51 public static void main(String[] args) { 52 Resource r=new Resource(); 53 Producer pro=new Producer(r); 54 Consumer con=new Consumer(r); 55 56 Thread t1=new Thread(pro); 57 Thread t2=new Thread(pro); 58 Thread t3=new Thread(con); 59 Thread t4=new Thread(con); 60 t1.start(); 61 t2.start(); 62 t3.start(); 63 t4.start(); 64 } 65 }
1.6.3、多线程升级锁Lock
JDK1.5中提供了多线程升级解决方案
将同步syn替换成现实Lock操作
将Object中的wait,notify,notifyAll,替换了Condition对象
该对象可以Lock锁,进行获取
实现了本方只唤醒对方操作
1 package learn; 2 3 import java.util.concurrent.locks.Condition; 4 import java.util.concurrent.locks.Lock; 5 import java.util.concurrent.locks.ReentrantLock; 6 7 class Resource{ 8 private String name; 9 private int count=1; 10 private boolean flag=false; 11 private Lock lock=new ReentrantLock(); 12 private Condition condition_pro=lock.newCondition(); 13 private Condition condition_con=lock.newCondition(); 14 public void set(String name)throws InterruptedException 15 { 16 lock.lock(); 17 try{ 18 while(flag) 19 condition_pro.await(); 20 this.name=name+"..."+count++; 21 System.out.println(Thread.currentThread().getName()+"生产者"+this.name); 22 flag=true; 23 condition_con.signal(); 24 } 25 finally{ 26 lock.unlock(); 27 } 28 29 } 30 public void out()throws InterruptedException{ 31 lock.lock(); 32 try{ 33 while(!flag) 34 condition_con.await(); 35 System.out.println(Thread.currentThread().getName()+"消费者............"+this.name); 36 flag=false; 37 condition_pro.signal(); 38 } 39 40 finally 41 { 42 lock.unlock(); 43 } 44 } 45 } 46 47 class Producer implements Runnable{ 48 private Resource res; 49 Producer(Resource res){ 50 this.res=res; 51 } 52 public void run(){ 53 try{ 54 while(true) 55 { 56 res.set("+商品+"); 57 } 58 } 59 catch(Exception e) 60 {} 61 } 62 } 63 64 class Consumer implements Runnable{ 65 private Resource res; 66 Consumer(Resource res){ 67 this.res=res; 68 } 69 public void run(){ 70 while(true) 71 { 72 try{ 73 res.out(); 74 } 75 catch(Exception e) 76 {} 77 } 78 } 79 } 80 public class ProducerConsumerDemo2 { 81 public static void main(String[] args) { 82 Resource r=new Resource(); 83 Producer pro=new Producer(r); 84 Consumer con=new Consumer(r); 85 86 Thread t1=new Thread(pro); 87 Thread t2=new Thread(pro); 88 Thread t3=new Thread(con); 89 Thread t4=new Thread(con); 90 t1.start(); 91 t2.start(); 92 t3.start(); 93 t4.start(); 94 } 95 }
1.7、如何停止线程?
stop方法已过时,只能让run方法结束,即控制run中的循环结束
特殊情况:
当线程处于冻结状态
就不会读取到标记,那么线程就不会结束
当没有指定的方式让冻结的线程回复到运行状态时,这时需要对冻结进行清除
强制让线程回复到运行状态中来,这样就可以操作标记让线程结束
interrput();方法
1.8、守护线程
1.9、join
当A线程执行到B线程的join方法时,A就会等到B执行完再执行
1 package pack; 2 class Demo implements Runnable 3 { 4 public void run(){ 5 for(int x=0;x<70;x++) 6 System.out.println(Thread.currentThread().getName()+"..."+x); 7 } 8 } 9 public class JoinDemo { 10 public static void main(String[] args) throws InterruptedException { 11 Demo d=new Demo(); 12 Thread t1=new Thread(d); 13 Thread t2=new Thread(d); 14 t1.start(); 15 //t1抢夺CPU执行权 16 t1.join(); 17 t2.start(); 18 19 for(int x=0;x<80;x++) 20 { 21 System.out.println("main..."+x); 22 } 23 System.out.println("over"); 24 } 25 }
1.9.1、线程优先级
所有线程默认优先级5,一共1-10级
1.9.2、yield();
尽量轮流执行
1.9.3、开发举例
1 package pack; 2 3 public class ThreadTest { 4 public static void main(String[] args) { 5 //匿名内部类更方便 6 new Thread() 7 { 8 public void run() 9 { 10 for(int x=0;x<100;x++) 11 { 12 System.out.println(Thread.currentThread().getName()+"..."+x); 13 } 14 } 15 }.start(); 16 17 for(int x=0;x<100;x++) 18 { 19 System.out.println(Thread.currentThread().getName()+"..."+x); 20 } 21 22 23 Runnable r=new Runnable(){ 24 public void run(){ 25 for(int x=0;x<100;x++) 26 { 27 System.out.println(Thread.currentThread().getName()+"..."+x); 28 } 29 30 } 31 }; 32 new Thread(r).start(); 33 } 34 } 35 36 //麻烦 37 //class Test1 extends Thread 38 //{ 39 // public void run() 40 // { 41 // for(int x=0;x<100;x++) 42 // System.out.println(Thread.currentThread().getName()); 43 // } 44 //}
黑马程序员——java学习6(127-151总结)——多线程
标签:
原文地址:http://www.cnblogs.com/sunxlfree1206/p/4679111.html