多线程

参考:https://blog.csdn.net/u012768459/article/details/80926112

一、进程和线程

进程:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
比如:QQ、微信就是两个进程
线程:是操作系统能够进行运算调度的最小单位
比如:一个mian方法就是一个主线程
一个进程通常包含多个线程,比如:微信一边放歌,一边看剧。

并发和并行

你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。

  • 并发:你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。

  • 并行:你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

  • 并发的关键是你有处理多个任务的能力,不一定要同时。

  • 并行的关键是你有同时处理多个任务的能力。

所以我认为它们最关键的点就是:是否是『同时』。

并发就是同步的串行,一个任务执行完执行下一个任务;

  • 同步: 多个任务情况下,一个任务A执行结束,才可以执行另一个任务B。只存在一个线程。

  • 异步: 多个任务情况下,一个任务A正在执行,同时可以执行另一个任务B。任务B不用等待任务A结束才执行。存在多条线程。

并行,在用同一个时刻执行多个线程;

二、多线程

实现多线的两种方式:继承java.lang.Thread类,实现java.lang.Runnable接口

原理:在单cpu上,cpu给多个线程分配执行时间段。

(一)、线程生命周期
  1. 新创建
  2. 就绪状态(可运行)
  3. 运行状态
  4. 等待状态
  5. 休眠状态
  6. 阻塞状态
  7. 死亡状态
(二)、线程休眠

Thread.sleep(毫秒数);//

	try {
				Thread.sleep(1000);//毫秒数
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
(三)、线程加入

如果存在一个A线程,现在需要加入B线程,并要求线程B执行完了才能再去执行A。

join():  B.join();    //在A线程的run()方法里使用
(四)、线程优先级

级别高的先执行概率大

  • 低优先级:1~4,其中类变量Thread.MIN_PRORITY最低,数值为1;

  • 默认优先级:如果一个线程没有指定优先级,默认优先级为5,由类变量Thread.NORM_PRORITY表示;

  • 高优先级:6~10,类变量Thread.MAX_PRORITY最高,数值为10。

设置线程优先级

   thread3.setPriority(MAX_PRIORITY);
(四)、线程礼让

yield(): 使具有至少同级别的优先级的线程有进入可执行状态的机会。

(五)、线程同步

保证线程安全性

(1)、synchronized 关键字:

1、同步块

synchronized (obj){
}

2、同步方法

public   synchronized      void medthod (){
}
(2)、加锁:
private Lock lock = new ReentrantLock();//获取一个锁对象
lock.lock(); //加锁
lock.unlock(); //解锁

三、实现runnable接口实现多线程

  1. 建立Runnable对象(实现类的实例化对象)
  2. 使用参数Runnable对象的构造方法创建Thread实例
  3. 调用start()方法启动线程
1、带synchorized的售票
public class SyncDemo implements Runnable{
	private int ticket = 50;
	public static void main(String[] args) {
		
		SyncDemo demo = new SyncDemo();
		
		Thread t1 =new Thread(demo); //必须传一个demo实例,才会有输出
		t1.setName("1号窗口");
		t1.start();
		Thread t2 =new Thread(demo);
		t2.setName("2号窗口");
		t2.start();
		Thread t3 =new Thread(demo);
		t3.setName("3号窗口");
		t3.start();

	}

	@Override
	public void run() {
		
		while (ticket > 0){
			sellTicket();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	/**
	 * synchronized关键字:同步方法
	 * 当一个线程启动并满足条件ticket>0,继而执行同步方法,此时,其它线程不能执行该方法,
	 * 一直等到该线程执行完了,其他线程才能执行该同步方法
	 * 缺陷:while处,可能有多个线程满足条件,继而去执行sellTicket()方法,其中一个线程获取同步方法锁
	 * 具备执行权限,直到此线程执行完,此时,tickets可能=0,但,其他线程可能之前满足tickets>0条件,
	 * 只是一直等待执行同步方法权限,这时正好获取到同步方法锁,继而去执行同步方法内的代码,导致tickets=0,或=-1
	 * 
	 * 
	 */
	public synchronized void sellTicket(){ //同步代码块
		System.out.println(Thread.currentThread().getName() + "卖了第" + ticket + "张票");
		ticket--;
	}
2、带lock的售票
package sunyard.fuza.thread.thread1;

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

public class TicketDemo {
	
	
   public static void main(String[] args) {
		Demo demo = new Demo();
		Thread t1 = new Thread(demo,"1");
		t1.setName("1号窗口:");
		Thread t2 = new Thread(demo,"2");
		t2.setName("2号窗口:");
		Thread t3 = new Thread(demo,"3号窗口:");//第二个参数相当于给线程一个名称
		//t3.setName("3号窗口:");
		t1.start();
		t2.start();
		t3.start();
		
	}
}


class Demo implements Runnable{
	
	private int ticket = 50;
	private Lock lock = new ReentrantLock();//获取一个锁对象
	@Override
	public void run() {
		while(ticket > 0){
			seelticket();
			try{
				Thread.sleep(1000);
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}
	/*
	 * 如果程序在执行try语句时,发生异常,继而去执行finally内的解锁语句,也会导致,多个窗口售卖同一张票
	 * 
	 */
	public void seelticket(){
		lock.lock(); //加锁
		try{
			if(ticket>0){			
				System.out.println(Thread.currentThread().getName() + "卖了第" + ticket + "张票!");
				ticket--;
			}
		}finally{
			lock.unlock(); //解锁
		}
	}
	
}

版权声明:本文为weixin_43976363原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。