黑马程序员——多线程



------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


兴趣是学习编程最好的老师

不积跬步,无以至千里

这辈子没办法做太多事情,所以每一件都要做到精彩绝伦。


1.线程是程序执行的一条路径, 一个进程中可以包含多条线程,多线程并发执行可以提高程序的效率, 可以同时完成多项工作。


2.开启新线程的两种方式
 1).继承Thread
  

public static void main(String[] args) {
	MyThread mt = new MyThread();		//4,创建自定义类对象
	mt.start();				<span style="font-family:宋体;">//5,开启线程
</span>	for(int i = 0; i < 10000; i++) {
	System.out.println("传智播客");
		}
	}

}

class MyThread extends Thread {		                //1,自定义类继承Thread
	public void run() {		                //2,重写run方法
		for(int i = 0; i < 10000; i++) {	//3,将要执行的代码写在run方法中
			System.out.println("黑马程序员");
		}
	}
}


 2).实现Runnable

public static void main(String[] args) {
		MyRunnable mr = new MyRunnable();//4,创建自定义类对象
		Thread t = new Thread(mr);	 //5,将自定义类对象当作参数传递给Thread的构造函数	
		t.start();			 //6,开启线程
		
		for(int i = 0; i < 10000; i++) {
			System.out.println("传智播客");
		}
	}

}

class MyRunnable implements Runnable {		//1,自定义类实现Runnable接口

	@Override
	public void run() {			//2,重写run方法
		for(int i = 0; i < 10000; i++) {//3,将要执行的代码写在run方法中
			System.out.println("黑马程序员");
		}
	}
}

3.Thread类常用方法
 获取名字: getName()方法
 设置名字:通过构造函数可以传入String类型的名字或通过setName(String)方法可以设置线程对象的名字
 获取当前线程对象:Thread.currentThread()
 休眠:Thread.sleep(毫秒,纳秒)
 守护:setDaemon()
 加入:

  join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续
  join(int), 可以等待指定的毫秒之后继续

 让出cpu:yield
 设置线程的优先级:setPriority()

public static void main(String[] args) {
		final Thread t1 = new Thread() {
			public void run() {
				for(int i = 0; i < 50; i++) {
					try {
						Thread.sleep(10);//休眠
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(getName() + "...传智播客");
				}
			}
		};
		
		Thread t2 = new Thread(new Runnable(){
			public void run() {
				for(int i = 0; i < 50; i++) {
				    if(i == 2) {
					try {
					//t1.join();//让出cpu,只有t1完全执行完,再执行t2
					t1.join(1);//让出cpu,但是只让出1毫秒,就是指定参数的时间
					} catch (InterruptedException e) {
							
						e.printStackTrace();
					}
					}
			System.out.println(Thread.currentThread().getName() + "...黑马程序员");
				} //获取当前线程对象
			}
		});
		t1.setDaemon(true);	//设置t1为守护线程
		t1.start();
		t2.start();
	}


4.线程之间的同步

 线程之间的同步有同步代码块和同步方法

 同步代码块是使用synchronized关键字加上一个锁对象来定义一段代码,多个同步代码块使用相同的锁对象
 同步方法是使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的,非静态同步方法默认使用当 前对象this作为锁对象,静态方同步函数的锁是该类的字节码对象。字节码对象可以认为是万能锁。

 要注意的是多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁,所以尽可能不要嵌套使用。

例如:模拟售票,总数为一千张,有四个窗口卖票:


public class Ticket {
	public static void main(String[] args) {
		new TicketsSeller().start();	//开启线程
		new TicketsSeller().start();
		new TicketsSeller().start();
		new TicketsSeller().start();
	}

}

class TicketsSeller extends Thread {
	private static int tickets = 1000;
	public void run() {
		while(true) {
			synchronized(TicketsSeller.class) {
				if(tickets == 0)	
					break;	
				try {
					Thread.sleep(10);//增强效果
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(getName() + "...这是第" + tickets-- + "号票");//卖票,并将结果--
			}
		}
	}
}

5.单例设计模式

单例设计模式:保证类在内存中只有一个对象。
 (1)将构造方法私有。
 (2)在本类中定义一个本类的对象。Singleton s;
 (3)提供公共的访问方式。public static Singleton getInstance(){return s}

 单例写法两种:饿汉式,懒汉式;

饿汉式:

class Singleton{
    private Singleton(){}
    private static Singleton s=new Singleton();
    public static Singleton getInstance(){
            return s;
      }
}

懒汉式:

class Singleton{
        private Sinleton(){}
        private static Singleton s;
        public static Sinleton getInstance(){
             if(s==null){
                s=new Sinleton();}
                return s;
          }
}


第三种格式:

class Singleton {
		private Singleton() {}

		public static final Singleton s = new Singleton();//final是最终的意思,被final修饰的变量不可以被更改
	}


6.线程之间的通信
  线程等待, wait()
  唤醒等待  notify();
  这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用
  多个线程通信的问题
  notify()方法是随机唤醒一个线程
  notifyAll()方法是唤醒所有线程
  JDK5之前无法唤醒指定的一个线程
  如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来反复判断条件

public class Demo6_Notify {
	public static void main(String[] args) {
		final Printer p = new Printer();
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

}

class Printer {
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized(this){
			if(flag != 1)
				this.wait();							//线程等待
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 2;								//flag改为2
			this.notify();								//唤醒等待的线程
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this){
			if(flag != 2) 
				this.wait();							//线程等待
			
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 1;								//flag改为1
			this.notify();								//唤醒等待的线程
		}
	}


7.JDK5之后的线程控制
 同步
  使用ReentrantLock类的lock()和unlock()方法进行同步
 通信
  使用ReentrantLock类的newCondition()方法可以获取Condition对象
  需要等待的时候使用Condition的await()方法, 唤醒的时候用signal()方法
  不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

package cn.itcast.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Demo8_ReentrantLock{
	public static void main(String[] args) {
		final Printer3 p = new Printer3();
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print1();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print2();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
		
		new Thread() {
			public void run() {
				while(true) {
					try {
						p.print3();
					} catch (InterruptedException e) {
						
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

}

class Printer3 {
	private ReentrantLock r = new ReentrantLock();			//创建锁对象
	private Condition c1 = r.newCondition();		        //添加监视器
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();
	private int flag = 1;
	public void print1() throws InterruptedException {
		r.lock();						//获取锁
			if(flag != 1)
				c1.await();				//线程等待
			System.out.print("传");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 2;				        //flag改为2
			c2.signal();					//唤醒线程2
		r.unlock();						//释放锁
	}
	
	public void print2() throws InterruptedException {
		r.lock();						//获取锁
			if(flag != 2) {
				c2.await();				//线程等待,2线程等待
			}
			System.out.print("黑");
			System.out.print("马");
			System.out.print("程");
			System.out.print("序");
			System.out.print("员");
			System.out.print("\r\n");
			flag = 3;					//flag改为3
			c3.signal();					//唤醒线程3
		r.unlock();						//释放锁
	}
	
	public void print3() throws InterruptedException {
		r.lock();						//获取锁
			if(flag != 3) {
				c3.await();				//线程等待,3线程等待
			}
			System.out.print("i");
			System.out.print("t");
			System.out.print("c");
			System.out.print("a");
			System.out.print("s");
			System.out.print("t");
			System.out.print("\r\n");
			flag = 1;					//flag改为1
			c1.signal();					//唤醒线程1
		r.unlock();						//释放锁
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值