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

------- 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++);
 }

}
//线程1
class Thr1 extends Thread{
 int count = 1;
  public void run(){
   for(int x=1;x<60;x++)
    System.out.println(this.getName()+"...run1..."+count++);
  }
}
//线程2
class 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学习型技术博客、期待与您交流! ----------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值