多线程是我们在开发当中经常会用到的知识点,这几天刚好在复习线程的知识点觉得这是一个比较重要的知识,在这里就做个笔记方便日后查看。
定义整理
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);
}
}