知识:
1,线程与进程:进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。一个进程中至少有一个线程。Java VM启动的时候会有一个进程java.exe,该进程至少一个线程负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程成为主线程。JVM启动的时候,还要产生一个垃圾回收机制的线程。多线程存在的意义:让程序中的各个部分产生同时的效果,一个进程中多个线程好像同时进行。
2,创建线程方法1---继承Thread类:(java.lang.Thread)步骤:继承Thread类;复写Thread类中的run方法;调用线程的start方法(该方法的作用:启动线程,调用run方法)多线程程序就相当于多个线程抢资源,因此随机性比较大
3,创建线程方法2---实现runnable接口:步骤:1, 定义类实现Runnable接口;2, 覆盖Runnable接口中的run方法;3, 通过Thread类建立线程对象;4, 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数;5, 调用Thread的start方法开启线程并调用Runnable接口子类的run方法
4,多线程安全问题的原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误;解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中其他线程不可以参与执行,java提供的解决方式是同步
5,同步代码块
Synchronized(对象){
需要被同步的代码
}
对象的参数是一个锁,同步锁,对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
同步的前提:必须要有两个或者两个以上的线程;必须是多个线程使用同一个锁。
同步好处:解决了多线程的安全问题;弊端:多个线程需要判断锁,较为消耗资源
6,同步函数
同步代码块的同步部分可以直接声明在函数上;而不是放在run上,放在run上就只有Thread0线程运行,而没有另一个线程运行;
同步函数的锁是this,因为函数被这个所属对象引用。
同步解决问题的方法:找到同步代码;明确共享数据;明确那部分的代码是操作共享数据的;带sleep测试可以找出程序中的问题
7,静态同步函数
静态同步函数的锁是class对象,因为静态没对象,而是通过类直接调用;而且静态进内存是在类加载进之后,对象创建之前;
8,单例设计模式中懒汉模式的同步处理:
懒汉式:
Class Single{
Private static Single s=null;
Private Single(){}
Public staticSingle getInstance(){
If(s==null){ //用双重判断的方式减少判断锁的次数,解决低效
Synchronized(Single.class) //静态的锁是当前的class文件
{ If(s==null){
S=new Single();
}
}
Return s;
}
}
9,死锁
同步中的嵌套同步,一直获不到资源
一个死锁程序:程序中。。。
10,线程间通信
多线程之间操作同一个资源,但是操作的动作不同。
等待唤醒机制:为了满足输出的顺序性,选择使用标记位,进入后进行判断,如果存入,就修改标记位,如果打印,打印之后再修改回去。
wait,notify,notifyAll:1:wait:让线程等待2:notify:唤醒线程池中的第一个线程3:notifyAll:唤醒线程池中的所有线程
为什么这些方法定义在了Object类中?1:这些方法存在与同步中。2:使用这些方法时必须要标识所属的同步的锁。3:锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。
wait(),sleep()有什么区别?wait()可有无参数的调用, 而sleep必须指定睡眠时间,但是有些时候,睡眠时间不好确定,这个时候就可以使用wait.;wait:释放了执行权,释放锁,sleep:释放了执行权,不释放锁;sleep有醒过来的时候,而wait可能醒不了.
11,生产者消费者
资源:里面有同步的set和get方法,set是供多个生产者加入,get是让多个消费者得到;
生产者:实现runnable接口,一个私有的资源,初始化传进一个资源实例,set操作放进复写的run里面。
消费者:实现runnable接口,一个私有的资源,初始化传进一个资源实例,get操作放进复写的run里面。
代码参照后面:
12,停止线程:通过stop方法停止线程.但是这个方法过时,所以不推荐使用;开启多线程,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束;
Thread.currentThread().getName():获得当前线程名字;
在run外部写上修改标记位。run判断不通过就退出了;特殊情况:当线程处于了冻结状态,就不会读取到标记,那么线程就不会结束;当没有指定的方式让冻结的线程恢复到运行状态是,这时需要对冻结进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束(Thread里面的方法 interrupt ------中断线程);
13,守护线程
Void setDaemon(Boolean on) 将线程标记为守护线程或用户线程;当正在运行的线程都是守护线程时,JVM退出
14,join方法
临时抢夺CPU执行权,用于临时加入线程执行
特点:当A线程执行到B线程的join方法时,A就会等待,当B线程都执行完,A才会执行。Join可以用来临时加入线程执行
15,优先级-yield方法
打印线程时调用toString()方法会按照[线程名称,优先权,线程所在的组名称]输出;默认优先级为5,主线程的优先级就是5;
Static void yield() 暂停当前正在执行的线程对象,并执行其他线程
T1.setPriority(Thread.MAX_PRIORITY).设置成线程的最高优先级10
优先级越高,运行的概率越高
16,线程的状态以及线程的常用方法:
线程的状态有就绪状态,运行状态,等待状态,休眠状态,终止状态,当条件齐备的时候就绪状态的线程就会开始执行。
wait()/notify()/notifyAll(): wait()之后线程释放锁进入等待状态,就绪状态的线程才可以利用锁;进入等待状态的线程只有通过notify()/notifyAll()才能够被唤醒(当条件发生变化)。和synchronized连用。
sleep(): 不释放琐,只是作一段时间的休眠,休眠完后继续执行。
yield(): 释放锁,使当前线程马上回到就绪状态,也可能马上在执行。
17,改进:
jdk1.5以后将同步和锁封装成了对象进行了优化。
Lock接口:出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成了显示锁操作。同时更为灵活,可以一个锁上加上多组监视器。
Condition接口:出现替代了object中的wait notify notifyAll方法。将这些监视器方法单独进行了封装,变成Condition监视器对象。可以和任意的锁进行组合。
将生产者消费者的代码优化。。
问题:
1,为什么要覆盖Thread类的run方法呢?Thread类用于描述线程。该类就定义了一个功能,用于存储线程要的代码,该存储功能就是run方法;也就是说,thread类中的run方法,用于存储线程要运行的代码;复写Thread类中的run方法 目的:将自定义的代码存储在run方法,让线程运行。
2,为什么要将Runnable接口的子类对象传递给Thread的构造函数?
因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法,就必须明确该run方法所属对象。
3,实现方式和继承方式有什么区别呢?继承Thread:线程代码存放Thread子类run方法中;实现Runnable,线程代码存放在接口的子类的run方法。实现的方式能避免单线程的局限性,所以建议使用实现接口的方法;Thread本身也实现Runnable接口
4,什么时候使用多线程?当某些代码同时被执行时,就用单独的线程进行封装,独立运算;多个之间相互不相干的时候封装成多线程。
程序:
死锁程序:http://zhidao.baidu.com/question/7744377.html
1 class Test implements Runnable 2 { 3 private boolean flag; 4 Test(boolean flag) 5 { 6 this.flag = flag; 7 } 8 9 public void run() 10 { 11 if(flag) 12 { 13 while(true) 14 { 15 synchronized(MyLock.locka) 16 { 17 System.out.println(Thread.currentThread().getName()+"...if locka "); 18 synchronized(MyLock.lockb) 19 { 20 System.out.println(Thread.currentThread().getName()+"..if lockb"); 21 } 22 } 23 } 24 } 25 else 26 { 27 while(true) 28 { 29 synchronized(MyLock.lockb) 30 { 31 System.out.println(Thread.currentThread().getName()+"..else lockb"); 32 synchronized(MyLock.locka) 33 { 34 System.out.println(Thread.currentThread().getName()+".....else locka"); 35 } 36 } 37 } 38 } 39 } 40 } 41 42 43 class MyLock 44 { 45 static Object locka = new Object(); 46 static Object lockb = new Object(); 47 } 48 49 class DeadLockTest 50 { 51 public static void main(String[] args) 52 { 53 Thread t1 = new Thread(new Test(true)); 54 Thread t2 = new Thread(new Test(false)); 55 t1.start(); 56 t2.start(); 57 } 58 } 59 /*两个锁是相互使用,很容易产生死锁,但也有可能会和谐*/
生产者消费者程序:
http://bbs.itheima.com/forum.php?mod=viewthread&tid=33523&page=1#pid195933
1 /* 2 生产者,消费者。 3 多生产者多消费者。 4 5 if判断标记只有一次,会导致不该运行的线程运行了,会出现数据错误的情况。 6 while判断标记,解决了线程获取执行权后,是否要运行。 7 8 notify:只能唤醒一个线程,如果唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。 9 notifyAll 解决了本方线程一定会唤醒对方线程的问题。 10 11 */ 12 class Resource2{ 13 private String name; 14 private int count = 1; 15 private boolean flag = false; 16 public synchronized void set(String name){ 17 while(flag) 18 try{this.wait();} 19 catch(InterruptedException e){} 20 this.name = name + count; 21 count++; 22 System.out.println(Thread.currentThread().getName()+"...生产者"+this.name); 23 flag = true; 24 notifyAll(); 25 } 26 public synchronized void get(){ 27 while(!flag) 28 try{this.wait();} 29 catch(InterruptedException e){} 30 System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name); 31 flag = false; 32 notifyAll(); 33 } 34 } 35 36 class Producer implements Runnable{ 37 Resource2 r; 38 Producer(Resource2 r){ 39 this.r = r; 40 } 41 42 public void run(){ 43 while(true){ 44 r.set("烤鸭"); 45 } 46 } 47 } 48 49 class Consumer implements Runnable{ 50 51 Resource2 r; 52 Consumer(Resource2 r){ 53 this.r = r; 54 } 55 public void run(){ 56 while(true){ 57 r.get(); 58 } 59 } 60 } 61 62 public class ConsumerDemo2 { 63 public static void main(String[] args) { 64 Resource2 r = new Resource2(); 65 66 Producer pro = new Producer(r); 67 Consumer con = new Consumer(r); 68 69 Thread t0 = new Thread(pro); 70 Thread t1 = new Thread(pro); 71 Thread t2 = new Thread(con); 72 Thread t3 = new Thread(con); 73 74 t0.start(); 75 t1.start(); 76 t2.start(); 77 t3.start(); 78 } 79 }
单例设计模式懒汉式:
1 /* 2 单例设计模式。 3 4 5 */ 6 //饿汉式。 7 /* 8 class Single 9 { 10 private static final Single s = new Single(); 11 private Single(){} 12 public static Single getInstance() 13 { 14 return s; 15 } 16 } 17 */ 18 19 20 //懒汉式 21 22 class Single 23 { 24 private static Single s = null; 25 private Single(){} 26 27 28 public static Single getInstance() 29 { 30 if(s==null) 31 { 32 synchronized(Single.class) 33 { 34 if(s==null) 35 //--->A; 36 s = new Single(); 37 } 38 } 39 return s; 40 } 41 } 42 43 class SingleDemo 44 { 45 public static void main(String[] args) 46 { 47 System.out.println("Hello World!"); 48 } 49 }
同步函数例子:
1 /* 2 需求: 3 银行有一个金库。 4 有两个储户分别存300员,每次存100,存3次。 5 6 目的:该程序是否有安全问题,如果有,如何解决? 7 8 9 如何找问题: 10 1,明确哪些代码是多线程运行代码。 11 2,明确共享数据。 12 3,明确多线程运行代码中哪些语句是操作共享数据的。 13 */ 14 class Bank 15 { 16 private int sum; 17 //Object obj = new Object(); 18 public synchronized void add(int n) 19 { 20 //synchronized(obj) 21 //{ 22 sum = sum + n; 23 try{Thread.sleep(10);}catch(Exception e){} 24 System.out.println("sum="+sum); 25 //} 26 } 27 } 28 class Cus implements Runnable 29 { 30 private Bank b = new Bank(); 31 public void run() 32 { 33 for(int x=0; x<3; x++) 34 { 35 b.add(100); 36 } 37 } 38 } 39 class BankDemo 40 { 41 public static void main(String[] args) 42 { 43 Cus c = new Cus(); 44 Thread t1 = new Thread(c); 45 Thread t2 = new Thread(c); 46 t1.start(); 47 t2.start(); 48 } 49 }