*进程:一个正在运行的程序,进程是操作系统分配资源的基本单位,每个进行有独立的内存空间,进程之间切换开销较大。
*线程:一个轻量级的进程,线程是任务调度的基本单位,一个进程可以有多个线程,
* 系统没有为线程分配额外的内存空间,一个进程中的多个线程共享内存空间,线程之间切换开销较小。
*创建线程的方式:
* 1.继承java.lang.Thread类,并重写run方法。
* 2.实现java.lang.Runnable接口,并重写run方法
*线程的启动:调用start()方法进行启动线程,而非调用run方法。
public class MyThread extends Thread{ public MyThread(String name){ super(name);//调用Thread的构造方法,分配新的 Thread 对象 } @Override public void run() { String name = getName();//获取线程的名称 for (int i = 0; i < 10; i++) { System.out.println(name+"---->"+i); } } }
public class MyThread2 implements Runnable{ private String name; public MyThread2(String name){ this.name=name; } @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(name+"======>"+i); } } }
public class Test { public static void main(String[] args) { MyThread thread1 = new MyThread("A"); MyThread2 thread2 = new MyThread2("B"); thread1.start();//启动线程A // thread1.run(); //方法调用 Thread t = new Thread(thread2);//创建代理 t.start();//启动线程B // t.run(); //方法调用 } }
代理模式:
public interface KindWoman { public void makeEyes(); }
public class PanJinLian implements KindWoman{ public void makeEyes(){ System.out.println("西门大官人,大郎出去卖了炊饼,今晚约吗?"); } }
public class YanPoXi implements KindWoman{ public void makeEyes(){ System.out.println("西门大官人,宋押司会见梁山好汉了,今晚约吗?"); } }
/** * 代理 */ public class WangPo { // PanJinLian panJinLian; KindWoman woman;//被代理者 public WangPo(KindWoman woman){ this.woman=woman; } public void makeEyes(){ System.out.println("西门大官人,我是王妈妈"); woman.makeEyes(); } public static void main(String[] args) { PanJinLian panJinLian = new PanJinLian(); WangPo wangPo = new WangPo(panJinLian); wangPo.makeEyes(); System.out.println("--------------------"); YanPoXi yanPoXi = new YanPoXi(); WangPo wangPo2 = new WangPo(yanPoXi); wangPo2.makeEyes(); } }
Thread种的方法:
*java.lang.Thread类
*常用构造方法:
* Thread()
* Thread(String name)
* Thread(Runnable target)
*常用的方法:
* getName():获取线程的名称
* getId():获取线程的标识符Id
* getState()返回该线程的状态。
* getPriority() 返回线程的优先级。
* void setPriority(int newPriority):更改线程的优先级
* NORM_PRIORITY:默认优先级,值为5
* MAX_PRIORITY:最高优先级,值为10
* MIN_PRIORITY:最低优先级,值为1
* setName(String name)改变线程名称,使之与参数 name 相同。
* sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
* start():启动线程***
* run():存放线程体中代码,不能显示调用。
* isAlive():判断线程是否还“活”着,即线程是未终止
public class MyThread2 extends Thread{ private String name;//线程名称 public MyThread2(String name){ this.name=name; } @Override public void run() { System.out.println("线程"+name+"开始执行...."); for (int i = 0; i < 10; i++) { // try { // Thread.sleep(1); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(name+"----->"+i); } System.out.println("线程"+name+"执行结束...."); } }
public class MyThread extends Thread{ private String name;//线程名称 public MyThread(String name){ this.name=name; } @Override public void run() { System.out.println("线程"+name+"开始执行...."); for (int i = 0; i < 10; i++) { // try { // Thread.sleep(1); // } catch (InterruptedException e) { // e.printStackTrace(); // } System.out.println(name+"----->"+i); try { join(1); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("线程"+name+"执行结束...."); } }
public class TestThread { public static void main(String[] args) { Thread t = Thread.currentThread();//获取当前线程 t.setPriority(Thread.MAX_PRIORITY);//设置优先级 t.setName("主线程"); System.out.println("线程名称:"+t.getName()); System.out.println("线程Id:"+t.getId()); System.out.println("线程的优先级:"+t.getPriority()); System.out.println("程序即将休眠1秒:"); try { t.sleep(1000);//单位是毫秒. } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前线程是否活着:"+t.isAlive()); System.out.println("休眠完毕!"); } }
public class TestMyThread { /*
Join () 阻塞指定线程等到另一个线程完成以后再继续执行
Sleep () 使线程停止运行一段时间,将处于阻塞状态
如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行!
yield () 让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态
如果调用了yield方法之后,没有其他等待执行的线程,这个时候当前线程就会马上恢复执行!
*/
public static void main(String[] args) { MyThread t1 = new MyThread("线程A"); MyThread2 t2 = new MyThread2("线程B"); // t1.setPriority(1); t1.start(); // t2.setPriority(10); t2.start(); } }
通过继承Thread类是不能用一个实例建立多个线程,故而实现Runnable接口适合于资源共享;
当然,继承Thread类也能够共享变量,能共享Thread类的static变量;
*模拟实现火车站售票窗口同时售票
* 50张车票,1000人在抢票
*Thread(Runnable target, String name) 分配新的 Thread 对象。
public class TicketSell implements Runnable{ private int ticket=100;//50张火车票 @Override public void run() { for(int i=1;i<=1000;i++){ Thread t = Thread.currentThread(); String name = t.getName(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } if(ticket>0){ System.out.println(name+"卖出了"+(ticket--)+"号票"); } } } public static void main(String[] args) { TicketSell ticketSell = new TicketSell(); Thread t1 = new Thread(ticketSell,"A窗口"); Thread t2 = new Thread(ticketSell,"B窗口"); Thread t3 = new Thread(ticketSell,"C窗口"); Thread t4 = new Thread(ticketSell,"D窗口"); Thread t5 = new Thread(ticketSell,"E窗口"); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
* 模拟实现火车站售票窗口同时售票 50张车票,1000人在抢票
* Thread(Runnable target, String name) 分配新的Thread 对象。
* 问题:多个窗口同时售票的过程中有可能出现同一张票出售给不同人。 解决方案:利用线程同步进行解决
* 同步:类似生活中排队,同一时刻只能有一个线程操作资源,在程序中可以通过加锁完成线程同步。
* 同步的优点:保证数据的有效性 同步的缺点:效率较低。
* 利用以下两种方式实现同步
* 1.在java中可以通过synchronized关键字(同步监视器)来实现同步. 同步监视器:synchronized(obj){ obj:同步监视器
* //代码; }
* 2.使用同步方法(使用synchronized关键字修饰的方法)进行加锁
public class TicketSell3 implements Runnable { private Integer ticket = new Integer(100);// 50张火车票 @Override public void run() { for (int i = 1; i <= 1000; i++) { Thread t = Thread.currentThread(); String name = t.getName(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } sale(name); } } /** * 同步的方法: * @param name */ public synchronized void sale(String name) { if (ticket > 0) { System.out.println(name + "卖出了" + (ticket--) + "号票"); } } public static void main(String[] args) { TicketSell3 ticketSell = new TicketSell3(); Thread t1 = new Thread(ticketSell, "A窗口"); Thread t2 = new Thread(ticketSell, "B窗口"); Thread t3 = new Thread(ticketSell, "C窗口"); Thread t4 = new Thread(ticketSell, "D窗口"); Thread t5 = new Thread(ticketSell, "E窗口"); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); } }
eg2:
public class BankAccount implements Runnable{ int blance=1000; @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name+"开始取款....."+blance); for(int i=1;i<10;i++){ try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } // synchronized (this) { //利用同步监视器实现线程同步 // if(blance>100){ // blance=blance-100; // System.out.println(name+"取款100,余额为:"+blance); // } // } draw(); } } /** * 利用同步方法实现线程同步 */ public synchronized void draw(){ String name = Thread.currentThread().getName(); if(blance>100){ blance=blance-100; System.out.println(name+"取款100,余额为:"+blance); } } public static void main(String[] args) { BankAccount bc = new BankAccount(); Thread t1 = new Thread(bc, "张三"); t1.start(); Thread t2 = new Thread(bc,"张三老婆"); t2.start(); } }
*死锁:当两个线程相互等待对方释放“锁”时就会发生死锁
*出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
*线程同步的优点:保证线程安全(数据安全有效)
*线程同步的缺点:效率低,有可能造成死锁问题。
public class TestDeadLock { public static void main(String[] args) { final DeadLock d1 = new DeadLock(); final DeadLock d2 = new DeadLock(); //使用匿名类创建线程 new Thread("线程A"){ public void run() { //调用d1的m1方法是需要对d2对象进行加锁 d1.m1(d2);//匿名类访问外部的成员变量时,该成员必须使用final修饰 }; }.start(); //使用匿名类创建线程 new Thread("线程B"){ public void run() { //调用d2的m1方法是需要对d1对象进行加锁 d2.m1(d1);//匿名类访问外部的成员变量时,该成员必须使用final修饰 }; }.start(); } }
public class DeadLock { public synchronized void m1(DeadLock deadLock){ String name = Thread.currentThread().getName(); System.out.println(name+"进入m1方法...."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name+"即将调用m2方法...."); deadLock.m2(); } public synchronized void m2(){ String name = Thread.currentThread().getName(); System.out.println(name+"进入m2方法...."); } }
*java.util.Timer类:定时器,一种工具,线程用其安排以后在后台线程中执行的任务
*java.util.TimerTask类实现Runnable接口,由 Timer 安排为一次执行或重复执行的任务。
*常用的构造方法:
* Timer()创建一个新计时器。
*常用的方法:
* schedule(TimerTask task, Date time)安排在指定的时间执行指定的任务。
* schedule(TimerTask task, long delay)安排在指定延迟后执行指定的任务。
* schedule(TimerTask task, Date firstTime, long period)
* 安排指定的任务在指定的时间开始进行重复的固定延迟执行。
* schedule(TimerTask task, long delay, long period)安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
public class MyTimerTask extends TimerTask{ @Override public void run() { System.out.println("执行了MyTimerTask中的run方法。"); } public static void main(String[] args) { Timer timer = new Timer(); // timer.schedule(new MyTimerTask(), new Date());//在当前时间执行MyTimerTask中的任务(调用其中run方法) // timer.schedule(new MyTimerTask(), 5000);//延迟5000毫秒执行任务调度(调用MyTimerTask中run方法) // timer.schedule(new MyTimerTask(),new Date(),2000);//从当前时间开始,每个2000毫秒做一次任务调度 timer.scheduleAtFixedRate(new MyTimerTask(), 5000, 2000);//延迟5000毫秒,每个2000毫秒执行一次任务调度 } }
生产者和消费者:
/** * 馒头类 * @author Administrator * */ public class SteamBread { private int id;//馒头的编号 public SteamBread(int id){ this.id=id; } @Override public String toString() { return "SteamBread [id=" + id + "]"; } }
/** * 盛放产品的容器(匡) * 1.生产者生成完产品之后将产品放入容器中,如果容器满了,停止生产并通知消费者进行消费 * 2.消费者从容器中取出产品进行消费,如果容器空了,停止消费并通知生产者者进行生成 * * @author Administrator * */ public class SyncStack { int index=0;//执行馒头的存储位置 SteamBread[] sb = new SteamBread[6];//容器 /** * 入栈:将生成者生成的馒头保存到匡中 */ public synchronized void push(SteamBread s){ //判断匡是否已满 if(index==sb.length-1){ try { this.wait();//停止生产 } catch (InterruptedException e) { e.printStackTrace(); } } this.notify();//唤醒消费者线程进行消费 //将馒头添加到匡中 sb[index++]=s; } /** * 出栈:消费者从匡中获取馒头 * @return */ public synchronized SteamBread pop(){ if(index==0){ try { this.wait();//停止消费 } catch (InterruptedException e) { e.printStackTrace(); } } this.notify();//唤醒生成者进行生产 this.index--;//push第n个之后,this.index++,使栈顶为n+1,故return之前要减一 return sb[index]; } }
/* * 生产者 * @author Administrator * */ public class Producer implements Runnable{ SyncStack ss;//匡 public Producer(SyncStack ss) { this.ss=ss; } @Override public void run() { for(int i=1;i<20;i++){ System.out.println("生产者开始生产---->"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } SteamBread s = new SteamBread(i); System.out.println("生产了:"+s); ss.push(s); } } }
/** * 消费者 * @author Administrator * */ public class Consume implements Runnable{ SyncStack ss;//匡 public Consume(SyncStack ss) { this.ss=ss; } @Override public void run() { for(int i=1;i<20;i++){ System.out.println("消费者开始消费---->"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } SteamBread s = ss.pop(); System.out.println("消费者拿走了---->"+s+"号馒头"); } } }
public class Test { public static void main(String[] args) { SyncStack ss = new SyncStack(); Producer producer = new Producer(ss); Consume consume = new Consume(ss); Thread t = new Thread(producer); Thread t2 = new Thread(consume); t.start(); t2.start(); } }