Java-多线程

Java多线程:java语言的一个优势就是处理多线程简单
    在一个操作系统中会同时运行多个任务(程序),例如:QQ、微信等
    1.在操作系统中同时运行的每一个任务都是一个进程
    2.对于一个进程(程序)而言,在程序内部也会同时运行多个任务,那个每一个任务称为一个线程
    
    线程的运行都是并发执行的,所谓的并发:宏观上所有的线程都是同时执行的,但是微观上所有的线程都是"走走停停"
    
    线程的调度:
    将CPU的时间划分为若干个时间片段,尽可能的均匀分配给每一个线程,获得CPU时间片段的线程将得以CPU执行
    
    创建线程的两种方式:Thread类  线程类
    其每一个实例表示一个可以并发的线程(匿名内部类)
    使用线程的注意事项:
    对于线程调度而言,分配的时间片段长短,具体分配给哪一个线程时间片段,对于程序而言,都是不可控制的
        * 使用多线程不考虑执行的先后顺序问题
        * 执行没有先后顺序的是异步运行(并发运行)--登录
        * 执行有先后顺序的是同步运行--银行取钱
        
    第一种创建线程的方式:继承Thread类
        第一种创建线程的方式存在弊端:
         * 线程与线程要干的事情(任务)耦合在一起
        * --启动线程是调用start方法,自动执行run方法
        *继承只能单继承
        
    第二种创建线程的方式:实现Runnable接口
        --将任务和线程解耦

    线程在执行某段逻辑时可以发生阻塞现象(控制自己不被执行)
    sleep阻塞:
    该阻塞可以指定阻塞时间,并在线程阻塞了该时间后自动返回runnable等待方法,Thread提供了一个静态方法sleep()用于睡眠阻塞
    
    线程阻塞在以下情况可以停止:
    1、run方法正常执行完毕
    2、run方法执行过程中抛出了一个未捕获的异常
    
    进程的停止:
    当一个进程中所有前台线程停止后,该进程结束
    
    前台线程和后台线程
    后台线程的特点:用法与前台线程无异,只是当一个进程中所有前台线程都结束后,
    无论后台线程是否还在运行中都被强制结束,从而使得进程结束,程序退出
    后台线程:也称为守护线程,或者精灵线程---lol开挂刷野时间盒
设置后台线程
    设置后台线程方法要在该线程被调用start()之前调用
    zhou.setDaemon(true);
    
    在运行我们的程序时,操作系统会启动一个进程来运行JVM,JVM运行后会创建第一个前台
    线程来运行我们的程序的main方法,同时也会创建一个后台线程来运行GC(垃圾回收机制)

线程的优先级:1-10(1最低、10最高)
    优先级越高的线程被分配时间片段的机会就越多,那么CPU执行的机会就越多
    
    线程安全:
    多线程并发访问同一资源时,会产生线程安全问题
    解决办法:并发即异步---将异步操作变成同步操作
    1、多线程并发读写同一临界资源会发生“线程安全并发问题”
        如果保证多线程同步访问临界资源,就可以解决安全问题。
    2、常见的临界资源:
        多线程共享的实例变量、静态的公共变量
    3、异步:各干各的  执行没有先后顺序      AJax
       同步:你干完我再干    执行有先后顺序
    4、同步锁:关键字synchronized----重要!!!
        synchronized可以修饰方法,当一个方法被修饰后,这个方法就是同步方法,同一刻只有一个线程访问该方法
    synchronized块
    当一个方法被修饰后,该方法变成同步方法,虽然保证了代码的执行安全,但是效率
    低下,我们实际上只需要将方法需要的同步片段加锁,这样可以缩小同步范围,从而
    提高代码的运行效率
    语法:
    synchronized(同步监视器){
        需要同步的代码片段
    }
    同步监视器:就是一个对象,任何对象都可以,可以new Object()
    但要保证一点,多线程看到的应该是"同一个"对象,通常情况下使用this

    非线程安全             线程安全
    StringBuilder        StringBuffer
    ArrayList            Vector
    HashMap              HashTable
    HashSet   ......
    对于集合Collection和Map而言
    Collections类提供了可以将给定的集合转换为线程安全的集合方法    
    list = Collections.synchronizedList(list);

    线程的协调工作:
    download.join();  //先执行download线程
    
    wait-notify
        使用wait()和notify()完成线程的协同工作
         * wait()阻塞会在以下两种情况被解除
            * 1.当download线程结束
            * 2.当调用了download的notify()
         * ---属于Object方法
                synchronized(object){
                object.wait();
        synchronized(object){
        //通知object身上的等待的线程解除阻塞
        object.notify();
        }

Day05
总结--创建线程的方式:
    1、继承Thread类
        实体类继承Thread类,覆盖run()方法,提供并发运行的过程
        创建这个类的实例    使用start()启动线程
    2、实现Runnable接口
    3、使用内部类/匿名内部类创建线程
    
线程的状态
    1、new 新建状态,还未启动
    
    2、Runnable    等待状态,可以运行状态(就绪)
    
    3、Ruuning    正在运行的状态,该线程已经获得了CPU
        a.假设线程获取了CPU,则进入Running状态,开始执行线程体
        
        b.假设系统只有一个CPU那么在任意时间点,只有一个线程属于Running
            如果是双核,那么在同一时间点,那么会有两条线程处于Running,但是当线程数大于处理器,依然会是多条线程在同一CPU轮换执行
            
        c.当一条线程开始运行的时候,如果不是一瞬间完成,那么它不可能一直处于
            Running状态,线程会在执行过程中被中断,目的是为了让其他线程获得执行机会,像这样的线程调度的策略取决于底层平台,对于抢占式策略的平台来说,
            系统会给每个可执行的线程一小段时间来处理任务,当该时间片段用完了,系统会剥夺线程所占资源(CPU),让其他线程获得运行机会
            
    4、block  阻塞或者挂起状态
        a.以下情况会发生阻塞状态
            1.线程使用了sleep()
            2.线程调用了阻塞式IO方法(比如控制台输入方法),在该方法放回前,该线程被阻塞
            3.join  wait-notify
        b.当正在执行的线程被阻塞时,其他线程就获得机会,阻塞结束的时候,该线程
            进入Runnable等待状态,而非直接进入Running状态
            
    5、dead    死亡状态
        run()执行结束,该线程进入死亡状态,不要试图对一个已经死亡的线程调用
        start(),死亡后不能再次作为线程执行,会抛出异常
    
线程的状态管理:
    1、Thread.sleep(times)
        使当前线程从Running放弃处理器进入block状态,休眠times毫秒,再返回Runnable状态,如果其他线程打断了当前线程的Block(sleep)
        就会发生中断异常InterruptedException
    2、Thread.yield()
        让出CPU,当线程让出处理器(离开Running),进入Runnable状态
        
线程的常用属性和方法:
    1.线程的优先级
        setPriorty
    2.后台线程(守护线程)
        线程对象引用名.setDaemon(true)
    3.获取线程的名字
        getName()
    4.获取当前线程
        Thread.currentThread()
    5.sleep状态的打断和唤醒
        Thread.sleep(times)
        引用名.interrupt()    被唤醒的线程会出现中断异常
        
线程池:Java1.5提供了并发包concurrent
    Executors是工厂,包含工厂用于创建Executor接口的实例
    Executor threadPools=Executors.newFixedThreadPool(2);
    Process p1=new Process();
    threadPools.execute(p1);//执行

创建线程的两张方式:

package day04;
//第一种创建线程的方式:继承Thread类
public class ThreadDemo01 {
	public static void main(String[] args) {
		Thread t1=new Person1();
		Thread t2=new Person2();
		//启动线程是调用start方法,自动执行run方法
		t1.start();
		t2.start();
		/*
		 * 使用多线程不考虑执行的先后顺序问题
		 * 执行没有先后顺序的是异步运行(并发运行)--登录
		 * 执行有先后顺序的是同步运行--银行取钱
		 */
	}
	/*
	 * 第一种创建线程的方式存在弊端:
	 * 线程与线程要干的事情(任务)耦合在一起
	 * --启动线程是调用start方法,自动执行run方法
	 */
}
class Person1 extends Thread{
	public void run(){
		for(int i=0;i<1000;i++){
			System.out.println("你是谁啊");
		}
	}
}

class Person2 extends Thread{
	public void run(){
		for(int i=0;i<1000;i++){
			System.out.println("我是收电费的");
		}
	}
}

 

package day04;
//第二种创建线程的方式:实现Runnable接口
//将任务和线程解耦
public class ThreadDemo02 {
	public static void main(String[] args) {
		//创建线程时再将任务指派
		Thread t1=new Thread(new PersonOne());
		Thread t2=new Thread(new PersonTwo());
		t1.start();
		t2.start();
	}
}
class PersonOne implements Runnable{
	public void run(){
		for(int i=0;i<1000;i++){
			System.out.println("你是谁啊");
		}
	}
}
class PersonTwo implements Runnable{
	public void run(){
		for(int i=0;i<1000;i++){
			System.out.println("查水表的");
		}
	}
}

 多线程Join:

package day04;
//线程的协调工作
public class JoinThreadDemo {
	//图片是否下载完毕
	public static boolean isFinish = false;
	public static void main(String[] args) {
		//下载图片的线程
		final Thread download = new Thread(){
			public void run(){
				System.out.println("download:开始下载图片");
				for(int i=0;i<=100;i++){
					System.out.println("download:已完成"+i+"%");
					try {
						Thread.sleep(50);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				System.out.println("download:图片下载完毕");
				isFinish = true;//表示图片下载完毕
			}
		};
		//显示图片的线程
		Thread showImg = new Thread(){
			public void run(){
				System.out.println("showImg:准备显示图片");
				//等待下载线程工作结束后,再执行下面的代码
				try {
					//先执行download
					download.join();
				} catch (Exception e) {
					e.printStackTrace();
				}
				if(!isFinish){
					throw new RuntimeException("图片没有下载完毕");
				}
				System.out.println("showImg:图片已经显示了");
			}
		};
		showImg.start();
		download.start();
		
	}
}

多线程wait()...notify()

package day05;
//使用wait()和notify()完成线程的协同工作
public class WaitAndNotifyDemo {
		public static boolean isFinish = false;
		public static Object object=new Object();
		public static void main(String[] args) {
			//下载图片的线程
			final Thread download = new Thread(){
				public void run(){
					System.out.println("download:开始下载图片");
					for(int i=0;i<=100;i++){
						System.out.println("download:已完成"+i+"%");
						try {
							Thread.sleep(50);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
					System.out.println("download:图片下载完毕");
					isFinish = true;//表示图片下载完毕
					synchronized(object){
						//通知object身上的等待的线程解除阻塞
						object.notify();
					}
				}
			};
			//显示图片的线程
			Thread showImg = new Thread(){
				public void run(){
					System.out.println("showImg:准备显示图片");
					//等待下载线程工作结束后,再执行下面的代码
					try {
						/*
						 * wait()阻塞会在以下两种情况被解除
						 * 1.当download线程结束
						 * 2.当调用了download的notify()
						 * ---属于Object方法
						 */
						synchronized(object){
							object.wait();
						}
						
					} catch (Exception e) {
						e.printStackTrace();
					}
					if(!isFinish){
						throw new RuntimeException("图片没有下载完毕");
					}
					System.out.println("showImg:图片已经显示了");
				}
			};
			download.start();
			showImg.start();
		}
		
	}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值