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

<pre name="code" class="html">
 

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

多线程   

我们学习的是多线程,那么要学习多线程,我们首先要学习线程.而线程是依赖于进程的,所有我们需要学习进程.
1. 什么是进程?
        通过任务管理器,可以查看到进程,所谓的进程就是正在执行的程序.
2. 多进程的意义?
       如果计算机是单进程,那么指定一次执行一个程序.而我们现在的计算机都是多进程. 那么也就是说我们可以一边玩游戏一边听音乐.
       提高CPU的使用率.
      我们一边 玩游戏一边听音乐.存在两个进程,那么这个两个进程是同时执行的吗?同时: 指的是在一个时间点
      不是同时执行的,因此CPU在一个时间点上只能执行一个任务,而我们看到的像是同时执行,其实是这样子的.是CPU在这个两个进程之间
  进行高效的切换.
  
3. 什么是线程?
一个应用程序可以执行多个任务,而每一个任务就是一个线程.
4. 多线程的意义?
多线程的意义不是提高程序的运行效率,而是提高程序的使用率.
如何理解这句话呢?
我们程序在执行的时候其实都是在抢占CPU的时间片(CPU的执行权). 如果一个应用程序只有一个任务,而另一个应用程序有多个任务,那么那个应用
抢占到CPU的执行权的概率大呢?是多个任务的应用程序抢到的概率比较大.多个任务的应用程序一定就可以抢占到CPU的执行权吗?不一定,所以多线程的执行具有随机性.


并发和并行的区别:
并发: 就是在一个时间点上

并行: 就是在一个时间段上

 实现多线程的两个方式:


   第一种方式:
   步骤:
  a: 创建一个类,然后让这个类继承Thread
  b: 重写run方法
  c: 创建该类的对象
  d: 启动线程类

public class ThreadDemo {
	
	public static void main(String[] args) {
		
		// 创建对象
		MyThread t1 = new MyThread() ;
		MyThread t2 = new MyThread() ;
		
		// 启动线程
		/**
		 * 不能使用run来启动线程,下边的代码其实只是在调用run方法
		 * 启动线程: 需要使用start方法
		 */
//		t1.run() ;
//		t1.run() ;
		
		// public void start()使该线程开始执行;Java 虚拟机调用该线程的 run 方法。 
		// 启动线程
		t1.start() ;
		t2.start() ;
		
		// java.lang.IllegalThreadStateException
		// 线程的启动只能是一次,不能进行多次启动
		// t1.start() ;
	}

}
package cn.itcast_test02;

/**
 * 为什么要重写run方法?
 * 我们现在的这个类是不是可以有多个方法? 可以存在多个方法.
 * 而我们的多个方法中的代码都是需要被线程执行的吗?不是的.
 * 如果我们想让某一段代码被线程执行,那么我们就把这个代码写在run方法 .
 * run方法中写的代码就是需要被线程执行的代码. 
 * 
 * 	run方法中的代码的特点:
 * 	写的代码都是比较耗时的代码
 */
public class MyThread extends Thread {

	@Override
	public void run() {
		for(int x = 0 ; x < 100 ; x++){
			System.out.println(x);
		}
	}
}


 如何来获取线程的名称以及给线程设置名称:
public final String getName(): 返回该线程的名称。 
public final void setName(String name)改变线程名称,使之与参数 name 相同。 

public class ThreadDemo {
	
	public static void main(String[] args) {
		
		// 创建对象
//		MyThread t1 = new MyThread() ;
//		MyThread t2 = new MyThread() ;
		
		// 使用构造方法给线程设置名称
		MyThread t1 = new MyThread("刘亦菲") ;
		MyThread t2 = new MyThread("公孙瓒") ;
		
		// 设置线程名称
//		t1.setName("刘亦菲") ;
//		t2.setName("公孙瓒") ;
//		
//		// 启动线程
		t1.start() ;
		t2.start() ;
		
		/**
		 * 获取主线程的名称: 如果我们可以获取当当前正在执行的线程,我们就可以获取到对应的名称
		 * 如何获取当当前正在执行的线程呢? 通过Thread类中的方法
		 * public static Thread currentThread()返回对当前正在执行的线程对象的引用。 
		 */
		// Thread.currentThread().setName("主线程") ;
		// System.out.println(Thread.currentThread().getName()) ;  // main
	}

}
package cn.itcast_test03;

public class MyThread extends Thread {
	
	public MyThread(){}

	public MyThread(String name){
		super(name) ;
	}
	
	@Override
	public void run() {
		for(int x = 0 ; x < 200 ; x++){
			System.out.println(getName() + "----" + x);
		}
	}
}



实现线程的第二种方式:
步骤:
a: 创建一个类,然后让这个类去实现Runnable接口
b: 复写run方法
c: 创建定义的类的对象
d: 创建Thread类的对象,然后把C中的对象作为参数传递进来
  e: 启动线程

public class ThreadDemo {
	
	public static void main(String[] args) {
		
		// 创建MyThread的对象
		MyThread my = new MyThread() ;
		
		// 创建Thread类的对象,然后把C中的对象作为参数传递进来
//		Thread t1 = new Thread(my) ;
//		Thread t2 = new Thread(my) ;
		
		/**
		 * 给线程设置名称
		 */
		Thread t1 = new Thread(my , "张三") ;
		Thread t2 = new Thread(my , "李四")  ;
		
		//启动线程
		t1.start() ;
		t2.start() ;
	}

}

package cn.itcast_test10;

public class MyThread implements Runnable {

	@Override
	public void run() {
		for(int x = 0 ; x < 200 ; x++){
			System.out.println(Thread.currentThread().getName() + "----" + x);
		}
	}

}


  这两种方式: 第二种方式相对比较友好一点点.因为其解决了继承带来的局限性


 线程的调度以及线程的优先级:
 调度模型:
  分时调度模型: 给每一个线程分配指定的时间,来完成线程的执行
   抢占式调度模型: 优先执行优先级高的线程,如果多个线程的优先级相同,随机执行一个
而我们的java语言采用的就是抢占式调度模型
 

线程的优先级:
如何来获取线程的优先级:
public final int getPriority() 返回线程的优先级。 
如何给线程设置优先级:
public final void setPriority(int newPriority):更改线程的优先级。 
线程的优先级存在一个范围: 这个范围是1-10
如果我们没有给线程设置优先级那么使用的就是默认的优先级: 5


线程控制

线程休眠:
public static void sleep(long millis)  throws InterruptedException: 参数表示的意思就是休眠的时间


  线程加入:
   public final void join(): 等待该线程终止

线程礼让:
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。 
 yield这个暂停线程的时间太短了,这时候别的线程有可能没有抢占到CPU的执行权,这时候该线程醒了,那么可以继续在和别的线程在抢占CPU的执行权

线程守护:
public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。

线程中断:
public final void stop(): 终止线程
public void interrupt(): 中断线程(这个翻译不太好),查看API可得当线程调用wait(),sleep(long time)方法的时候处于阻塞状态,可以通过这个方法清除阻塞


我们线程中产生问题的标准:
a: 是否是多线程环境
b: 是否存在共享数据
c: 是否有多条语句操作共享数据

如何来解决这个问题呢?
我们可以让一个线程执行操作共享数据的代码,然后其他的线程处于等待状态. 
 如何让一个线程执行这段代码的同时,其他线程处于等待状态呢?

等待唤醒机制


 需要使用同步代码块:
  格式:
synchronized(对象){
  需要被同步的代码 ;
}
同步代码块保证同步的作用的关键是这个对象,其实这个对象可以被看做成一把锁.有的书上把这个对象称之为监视器
这个同步代码块中的对象要保证多个线程使用的是一个

同步代码块的好处: 提高了数据的安全性
  同步代码块的弊端: 每一个线程进来以后都需要判断同步锁,所有对应的效率比较低

public class ThreadTest {
	
<span style="white-space:pre">	</span>public static void main(String[] args) {

	// 创建SellTickets对象
	SellTickets st = new SellTickets() ;
		
	// 创建Thread对象
	Thread t1 = new Thread(st , "窗口1") ;
	Thread t2 = new Thread(st , "窗口2") ;
		Thread t3 = new Thread(st , "窗口3") ;
		
		// 启动线程
		t1.start() ;
		t2.start() ;
		t3.start() ;
		
		
	}
package cn.itcast_test14;

public class SellTickets implements Runnable {
	
	/**
	 * 定义票数
	 */
	<span style="white-space:pre">	</span>private static int tickets = 100 ;
	<span style="white-space:pre">	</span>private static Object obj = new Object() ;

	@Override
	public void run() {
		while(true){
		synchronized(obj){
				if(tickets > 0){
					try {
						Thread.sleep(100) ;
					} catch (InterruptedException e) {
						e.printStackTrace();
				}
					System.out.println(Thread.currentThread().getName() + "出售第" + (tickets--) + "张票");
				}
			}
		}
<span style="white-space:pre">	</span>}
}


同步代码块以及同步方法和静态同步方法的锁对象?

  同步代码块的锁是, 是任意的对象
  同步方法的锁对象到底是谁呢? 是this
  静态同步方法的锁对象到底是谁呢? 是当前类的字节码文件对象

package cn.itcast_test15;

/*
 * 同步代码块的锁是,是任意的对象
 * 同步方法的锁对象到底是谁呢?			是this
 * 静态同步方法的锁对象到底是谁呢?		是当前类的字节码文件对象
 */
public class ThreadTest {
	
<span style="white-space:pre">	</span>public static void main(String[] args) {

		// 创建SellTickets对象
		SellTickets st = new SellTickets() ;
		
		// 创建Thread对象
		Thread t1 = new Thread(st , "窗口1") ;
	<span style="white-space:pre">	</span>Thread t2 = new Thread(st , "窗口2") ;
		Thread t3 = new Thread(st , "窗口3") ;
		
		// 启动线程
		t1.start() ;
		t2.start() ;
		t3.start() ;
		
	}
}
package cn.itcast_test15;

public class SellTickets implements Runnable {
	
	/**
	 * 定义票数
	 */
	private static int tickets = 100 ;
	private static Object obj = new Object() ;
<span style="white-space:pre">	</span>private int n = 0 ;

	@Override
	public void run() {
		while(true){
			
			if(n % 2 == 0){
				synchronized(SellTickets.class){
					if(tickets > 0){
						try {
							Thread.sleep(100) ;
						} catch (InterruptedException e) {
				<span style="white-space:pre">	</span>		e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName() + "出售第" + (tickets--) + "张票");
					}
				}
			}else {
				sellTicket() ;
			}
			n++ ;
		}
	}
	
//	public void sellTicket() {
//		synchronized(obj){
//			if(tickets > 0){
//				try {
//					Thread.sleep(100) ;
//				} catch (InterruptedException e) {
//					e.printStackTrace();
//				}
//				System.out.println(Thread.currentThread().getName() + "出售第" + (tickets--) + "张票");
//			}
//	}
//	}
	
	/**
	 * 同步方法
 */
//	public synchronized void sellTicket() {
//		if(tickets > 0){
//			try {
//				Thread.sleep(100) ;
//		} catch (InterruptedException e) {
//				e.printStackTrace();
//			}
//	<span style="white-space:pre">	</span>System.out.println(Thread.currentThread().getName() + "出售第" + (tickets--) + "张票");
//	}
//	}
	
	public static synchronized void sellTicket() {
		if(tickets > 0){
			try {
				Thread.sleep(100) ;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "出售第" + (tickets--) + "张票");
		}
	}
}

死锁

package cn.itcast_test02;

/**
 * 死锁: 是多个线程在抢占CPU的资源的时候,出现了相互等待的状态就叫死锁
 * 举例:
 * 	中国人和美国人吃饭使用的餐具
 *
 * 		中国人使用的是筷子
 *		美国人使用的是刀和叉子
 * 		
 * 	中国人拿了美国人的刀
 * 		美国人拿了中国人的一个筷子
 *
public class ThreadDemo {
	
	public static void main(String[] args) {
		
		// 创建线程对象
	<span style="white-space:pre">	</span>MyThread t1 = new MyThread(true) ;
		MyThread t2 = new MyThread(false) ;
		
		// 启动线程
		t1.start() ;
		t2.start() ;
		
	}

}
public class MyThread extends Thread {
	
	private boolean flag ;
	public MyThread(boolean flag){
		this.flag = flag ;
	}
	
	@Override
	public void run() {
		
		if(flag){
		
			synchronized(MyLock.objA){
				System.out.println("true....objA......");
<span style="white-space:pre">	</span>		synchronized(MyLock.objB){
					System.out.println("true....objB.....");
				}
			}
			
		}else {
			
			synchronized(MyLock.objB){
				System.out.println("false....objB......");
				synchronized(MyLock.objA){
					System.out.println("false....objA.....");
				}
			}
		}
		
	}

}

线程的五种状态


线程的生命周期:



 

同步代码块以及同步方法和静态同步方法的锁对象?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值