4、线程类笔记

多线程是我们在开发当中经常会用到的知识点,这几天刚好在复习线程的知识点觉得这是一个比较重要的知识,在这里就做个笔记方便日后查看。

定义整理

1、多线程多线程可以实现多段代码“同时运行”的效果,实际上是并发运行

创建线程方式1

第一种创建线程的方式比较简单,适合使用匿名内部类快速创建临时线程跑任务
但是它也存在两种设计不足:
1、由于需要继承Tread,而java又是单继承的,这就是导致若继承了Tread就
无法再继承其他雷区复用方法。这在时间开发中会出现比较多的矛盾
2、继承Thread后需要重写run方法来定义任务,这就导致了线程与线程要执行
的任务之间存在必然的耦合关系,导致线程重用性差

/**
 * 多线程多线程可以实现多段代码“同时运行”的效果,实际上是并发运行
 * 创建线程有两种方式:
 * 1、继承Thread并且重写run方法,run方法的作用时定义该线程
 * 		要执行的任务
public class ThreadDemo1 {

	public static void main(String[] args) {
		MyThread1 mt1 = new MyThread1();
		MyThread2 mt2 = new MyThread2();
		/*
		 * 启动线程要调用start方法,而不是直接调用run方法
		 * 当一个线程的start方法调用完毕后,该线程会被纳入
		 * 到线程调度中,一旦被分配CPU时间片,该线程会自动
		 * 的执行其run方法开始运行任务,所以一个线程的start
		 * 方法执行后run方法会很快的被运行起来
		 */
//		mt1.start();
//		mt2.start();
		Thread myThread3=new MyThread3();
//		myThread3.start();

        ThreadDemo1 t=new ThreadDemo1();
        t.thread.start();
	}

	Thread thread=new Thread(){
        @Override
        public void run() {
            for(int i=0;i<50;i++){
                System.out.println("我是匿名内部类创建的线程");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
}

class MyThread1 extends Thread{
	public void run() {
		for(int i = 0;i < 1000;i++) {
			System.out.println("你谁啊?");
		}
	}
}
class MyThread2 extends Thread{
	public void run() {
		for(int i = 0;i < 1000;i++) {
			System.out.println("我是查水表的!");
		}
	}
}

class MyThread3 extends Thread{
	public void run(){
		for(int i=0;i<5;i++){
			System.out.println("20190427");
		}
	}
}

创建线程方式2

第二种创建线程的方式实现Runnable接口,单独定义线程任务,建议使用

public class ThreadDemo2 {
	public static void main(String[] args) {
		//实例化任务
		Runnable r1 = new MyRunnable1();
		Runnable r2 = new MyRunnable2();
		//实例化线程
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r2);
		//启动线程
//		t1.start();
//		t2.start();
		Runnable myThread3=new MyRunable3();
		Thread t3=new Thread(myThread3);
		t3.start();	
	}
}
class MyRunnable1 implements Runnable{
	public void run() {
		for (int i = 0; i < 1000; i++) {
			System.out.println("杀对方啦");
		}
	}
}
class MyRunnable2 implements Runnable{
	public void run() {
		for (int i = 0; i < 1000; i++) {
			System.out.println("随军礼服");
		}
	}	
}

class MyRunable3 implements Runnable{

	@Override
	public void run() {
		for(int i=0;i<5;i++){
			System.out.println("20190428");
		}
	}
}

创建线程方式3

使用匿名内部类创建形式完成两种线程的创建方式

public class ThreadDemo3 {
	public static void main(String[] args) {
		//方式1
		Thread t1 = new Thread() {
			@Override
			public void run() {
				for (int i = 0; i < 1000; i++) {
				System.out.println("你谁啊?");	
				}
			}
		};		
		//方式2
		Runnable r2 = new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 1000; i++) {
					System.out.println("查水表的!");
				}
			}
		};
 		Thread t2 = new Thread(r2);
 		
 		t1.start();
 		t2.start();
	}
}

线程池

线程池
线程池主要的两个作用:
1、控制线程数量
2、重用线程
线程数量过多会导致内存消耗大,并且会产生CPU过渡切换导致整体并发
性能降低的问题,并且频繁的创建爱你销毁线程也会给系统带领负担,为
此在实际开发中出现上述情况时,我们都应当使用线程池
(简单理解为,固定一次最多运行线程的数量,比如设置5个线程,而又10个线程任务要执行,程序只会先开启五个任务在这个5个线程池里面运行,当有线程空出来的时候会再去执行剩余的线程任务)

public class ThreadPoolDemo {
	public static void main(String[] args) {
		ExecutorService threadPool = Executors.newFixedThreadPool(2);
		for (int i = 0; i < 5; i++) {
			Runnable runn = new Runnable() {

				@Override
				public void run() {
					//获取到线程对象
					Thread t = Thread.currentThread();
					System.out.println(t.getName() + ":正在运行");
					try {
						Thread.sleep(5000);
						System.out.println(t.getName() + ":运行结束");
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			};
			//将任务交给线程池
			threadPool.execute(runn);
			System.out.println("指派量一个任务给线程");
		}
		threadPool.shutdown();
	}
}

常用API

join

package thread;
/**
 * 多个线程之间的异步运行代码的(各自代码运行之间不存在先后关系,各干各的)
 * 同步运行:执行有先后顺序,通过单线程运行代码是同步
 * 异步运行:各干各的,多线程执行就是异步执行
 * 
 * 线程提供了:
 * void join()
 *  该方法允许一个线程在join方法所属线程后面等待,直到该线程执行完毕后再继续
 *  运行,所以使用join可以协调线程之间同步运行代码。
 *  
 * @author soft01
 *
 */
public class JoinDemo {
	public static boolean isFinish = false;
	public static void main(String[] args) {
		Thread download = new Thread() {
			public void run() {
				System.out.println("开始下载图片");
				for (int i = 0; i <= 100; i++) {
					System.out.println("down:" + i + "%");
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println("图片下载完毕");
				isFinish = true;
			}
		};
		Thread show = new Thread() {
			public void run() {
				System.out.println("show:开始显示图片");
				/*
				 * 加载图片前应当等待下载线程将图片下载完毕
				 */
				try {
					/*
					 * JDK1.8之前有一个要求,源自JVM内存分配问题L
					 * 当一个方法的局部内部类当中想引用该方法的其他
					 * 局部变量时,该变量必须使用fina修饰的。
					 * 这里main方法的局部内部类show当中想引用download,
					 * 而download本身是main方法的一个局部变量,
					 * 那么该变量就必须是final修饰
					 */
					download.join();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				if(!isFinish) {
					//模拟加载图片失败
					/*
					 * 当一个线程在run方法抛出了一个异常
					 * 意味着该线程就会结束
					 */
					throw new RuntimeException("图片加载失败");
				}
				System.out.println("show:显示图片");
			}
		};
		download.start();
		show.start();
	}
}

常用API 2

①Thread提供了一个静态方法
static Thread currentThread() 获取到运行该方法的线程并将其返回后面会有一个很重要的API:ThreadLocal,就是利用这个方法解决问题的。包括后期spring中使用aop管理事务时就用到了这个操作.


package thread;
/**
 * 获取线程相关的信息的一组方法
 * @author soft01
 *
 */
public class InfoDemo {
	public static void main(String[] args) {
		//获取main线程
		Thread main = Thread.currentThread();
		/*
		 * 获取线程名字
		 * String getName()
		 */
		String name = main.getName();
		System.out.println("线程名称:" + name);
		/*
		 * 获取唯一标识
		 * long getId()
		 */
		long id = main.getId();
		System.out.println("线程ID:" + id);
		/*
		 * 获取线程优先级
		 * int getPriority();
		 */
		int priority = main.getPriority();
		System.out.println("线程的优先级:" + priority);
		
		/*
		 * 判断线程是否处于活动状态
		 * boolean isAlive()
		 */
		boolean isAlive = main.isAlive();
		System.out.println(isAlive);
		/*
		 * 判断线程时父为守护线程
		 * boolean isDaemon()
		 */
		boolean isDaemon = main.isDaemon();
		System.out.println(isDaemon);
		/*
		 * 判断线程是否被中断
		 * boolean isInterrupted()
		 */
		boolean isInterrupted = main.isInterrupted();
		System.out.println(isInterrupted);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值