黑马程序员_java基础--多线程

来源:互联网 发布:淘宝店面设计 知乎 编辑:程序博客网 时间:2024/06/07 04:20
------- android培训、java培训、java学习型技术博客、期待与您交流! ----------

多线程

1、线程类和实现多线程
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:程序中的控制单元,线程在控制着进程的执行。

一个进程至少有一个线程。

Java VM 启动的时候会有一个进程java.exe。存在主线程,这个线程运行的代码存在于main方法中。
1.1、继承Thread类
定义类继承Thread.
复写Thread类中的run方法。
创建实例调用线程的start方法,该方法作用:启动线程,调用run方法。
如:

public class TreadDemo { //主线程 public static void main(String[] args) {  // TODO Auto-generated method stub  Thr1 t1 = new Thr1();  Thr2 t2 = new Thr2();//创建线程实例  t1.start();//调用start方法开启线程  t2.start();  int count = 1;  for(int x=1;x<70;x++)   System.out.println(Thread.currentThread().getName()+"..main...."+count++); }}//线程1class Thr1 extends Thread{ int count = 1;  public void run(){   for(int x=1;x<60;x++)    System.out.println(this.getName()+"...run1..."+count++);  }}//线程2class Thr2 extends Thread{ int count = 1; public void run(){  for(int y=1;y<60;y++)   System.out.println(this.getName()+"..run2....."+count++); }}

 

运行结果每次都不同
随机性

为什么要覆盖run方法呢?
Thread类用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码。该存储功能就是run方法。

run和start方法.

状态图:

                                                                                                图 1-1
线程标识:名称:getName();线程拥有默认的名称:Thread-编号
void setName(String name) 改变线程名称,使之与参数 name 相同。
void setPriority(int newPriority) 更改线程的优先级。
Thread.currentThread()==this;获取当前线程。
sleep方法需要制定睡眠时间,单位是毫秒。一个特殊的状态:就绪。具备了执行资格,但是还没有获取资源。
static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
void join() 调用该方法的线程需要执行完毕其他线程才会执行。
void interrupt() 束线程的冻结状态,使线程回到运行状态中来

1.2、实现Runnable接口。

class PrimeRun implements Runnable {         long minPrime;         PrimeRun(long minPrime) {             this.minPrime = minPrime;         }          public void run() {             // compute primes larger than minPrime              //. . .         }     }

 

然后,下列代码会创建并启动一个线程:
     PrimeRun p = new PrimeRun(143);
     new Thread(p).start();
1.3 两种方法的区别
继承Thread:线程代码存放在Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法。

实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

 

售票例子:
多窗口售票
无效线程异常

public class TicketDemo { /**  * @param args  */ public static void main(String[] args) {  Ticket tick = new Ticket();  Thread t1 = new Thread(tick);  Thread t2 = new Thread(tick);  Thread t3 = new Thread(tick);  Thread t4 = new Thread(tick);  t1.start();  t2.start();  t3.start();  t4.start(); }}class Ticket implements Runnable{ private int tickNum = 10; Object obj = new Object(); @Override public void run() {  while(true){   synchronized(obj){    if(tickNum>0){     try{Thread.sleep(20);}catch(Exception e){}     System.out.println(Thread.currentThread().getName()+"..run.."+tickNum--);    }   }    }   }}


2、多线程安全问题---同步
问题的原因:
 当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
 另一个线程参与进来执行。导致共享数据的错误。
解决办法:
 对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
同步代码块
synchronized(对象)
{
 需要同步的代码
}
对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。
共享数据
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
必须保证同步中只能有一个线程在运行。
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源,

同步函数
锁:this
同步静态函数
锁:类名.class
同步函数的锁是固定的this。
同步代码块的锁是任意的对象。
建议使用同步代码块。

单例设计模式
懒汉式
实例的延迟加载

class Single{ private Single(){} private static Single s = null; public static Single getInstance(){  if(s==null){   synchronized(Single.class){    if(s==null)     s=new Single();   }  }  return s; }}


典型死锁:

public class DeadLockDemo { /**  * @param args  */ public static void main(String[] args) {  Thread t1 = new Thread(new Test(true));  Thread t2 = new Thread(new Test(false));  t1.start();  t2.start(); }}class MyLock{ //定义两把锁 static Object locka = new Object(); static Object lockb = new Object();}class Test implements Runnable{ private boolean flag; Test(boolean flag){  this.flag = flag; } public void run(){  if(flag){   while(true){    synchronized(MyLock.locka){     System.out.println("if locka");     synchronized(MyLock.lockb){      //....      System.out.println("if lockb");     }    }   }  }else{   while(true){    synchronized(MyLock.lockb){     System.out.println("else lockb");     synchronized(MyLock.locka){      //...      System.out.println("else locka");     }    }   }  } }}

 

3、线通信程间
存在安全问题,怎么解决这个问题呢?

等待唤醒机制
wait();
notify();
notifyAll();
为什么定义notifyAll,
因为需要唤醒对方线程。
因为只用notify,容易出现只唤醒本方线程的情况。导致程序中的所有线程都等待。

生产消费者
多个生产消费
while
notifyAll

public class ProCsuDemo { /**  * @param args  */ public static void main(String[] args) {  Resource res = new Resource();  Producer pro = new Producer(res);  Consumer con = new Consumer(res);  Thread t1 = new Thread(pro);  Thread t2 = new Thread(con);  Thread t3 = new Thread(pro);  Thread t4 = new Thread(con);  t1.start();  t2.start();  t3.start();  t4.start(); }}class Resource{ private int count = 1; private String name; private boolean flag = false; public synchronized void set(String name){  while(flag){   try {    this.wait();   } catch (InterruptedException e) {    e.printStackTrace();   }  }  this.name = name +"--"+ (count++);  System.out.println(Thread.currentThread().getName()+".....生产者..."+this.name);  flag = true;  this.notifyAll(); } public synchronized void out(){  while(!flag){   try {    this.wait();   } catch (InterruptedException e) {    e.printStackTrace();   }  }   System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);  flag = false;  this.notifyAll(); }}class Producer implements Runnable{ private Resource res; Producter(Resource res){  this.res = res; } @Override public void run() {  while(true){   res.set("+商品+");  } } }class Consumer implements Runnable{ private Resource res; Consumer(Resource res){  this.res = res; } public void run(){  while(true){   res.out();  } }}

 

4、JDK1.5的新特性
java.util.concurrent.locks
Lock类
上锁
lock();
解锁
unlock();
Condition类
await();
signal();
signalAll();

class X {   private final Lock lock = new ReentrantLock();   // ...   public void m() {      lock.lock();  // block until condition holds     try {       // ... method body     } finally {       lock.unlock()     }   } }

生成消费者

import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ProCsuDemo2 { /**  * @param args  */ public static void main(String[] args) {  Resource2 res = new Resource2();  Producter2 pro = new Producter2(res);  Consumer2 con = new Consumer2(res);  Thread t1 = new Thread(pro);  Thread t2 = new Thread(con);  Thread t3 = new Thread(pro);  Thread t4 = new Thread(con);  t1.start();  t2.start();  t3.start();  t4.start(); }}class Resource2{ private int count = 1; private String name; final Lock lock = new ReentrantLock(); final Condition con_pro  = lock.newCondition();  final Condition con_csu = lock.newCondition();   private boolean flag = false; public void set(String name){  lock.lock();  try {   while(flag){    con_pro.await();   }   this.name = name +"--"+ (count++);   System.out.println(Thread.currentThread().getName()+".....生产者..."+this.name);   flag = true;   con_csu.signal();  } catch (Exception e) {   e.printStackTrace();  }finally{   lock.unlock();  } } public void out(){  lock.lock();  try {   while(!flag){    con_csu.await();   }    System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);   flag = false;   con_pro.signal();  } catch (Exception e) {   e.printStackTrace();  }finally{   lock.unlock();  } }}class Producter2 implements Runnable{ private Resource2 res; Producter2(Resource2 res){  this.res = res; } @Override public void run() {  while(true){   res.set("+商品+");  } } }class Consumer2 implements Runnable{ private Resource2 res; Consumer2(Resource2 res){  this.res = res; } public void run(){  while(true){   res.out();  } }}

停止线程。
stop方法过时了
控制run方法控制线程结束。
Thread类
interrupt();冻结状态的线程强制清除。
守护线程:
setDaemon(true);
----------------
join();
申请加入执行,要执行权,结束之后其他线程才能执行。

优先级有1-10个等级
setPriority();
默认优先级为5;
MAX_PRIORITY
MIN_PRIORITY
NORM_PRIROITY

yield()方法;
稍微减少线程执行频率,暂停正在执行的线程,并执行其他线程。

使用匿名内部类书写线程
Thread t = new Thread(new Runnable(){
 public void run(){}
});
t.start();

停止线程:
1,stop方法。
2,run方法结束。
怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务。
控制循环通常就用定义标记来完成。
但是如果线程处于了冻结状态,无法读取标记。如何结束呢?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。
当时强制动作会发生了InterruptedException,记得要处理

5、线程池(重要)jdk1.5新特性

java.util.concurrent包提供了线程池的实现

                                                               图 5-1

                                                                                图 5-2

------- android培训、java培训、java学习型技术博客、期待与您交流! ----------
原创粉丝点击